PBox y NBox funcionando

This commit is contained in:
Miguel 2025-04-19 01:47:12 +02:00
parent d6125f9433
commit 45c34c7dca
11 changed files with 720 additions and 1259 deletions

View File

@ -109,17 +109,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gSLIM_Sec\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gSLIM_Sec\""
}
},
"outputs": {
@ -168,18 +168,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_pin": "out"
}
},
"outputs": {
@ -258,17 +258,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
}
},
"outputs": {
@ -374,18 +374,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
}
},
"outputs": {
@ -416,17 +416,17 @@
"datatype": "Int",
"value": 1
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "24",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
},
"en": {
"type": "connection",
"source_instruction_uid": "27",
"source_instruction_type": "Contact",
"source_pin": "out"
}
},
"outputs": {
@ -532,18 +532,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
}
},
"outputs": {
@ -574,17 +574,17 @@
"datatype": "Int",
"value": 1
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
},
"in1": {
"uid": "24",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdHour\""
},
"en": {
"type": "connection",
"source_instruction_uid": "30",
"source_instruction_type": "Contact",
"source_pin": "out"
}
},
"outputs": {
@ -615,17 +615,17 @@
"datatype": "Int",
"value": 1
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
},
"in1": {
"uid": "27",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gBlendingMaintHour\""
},
"en": {
"type": "connection",
"source_instruction_uid": "30",
"source_instruction_type": "Contact",
"source_pin": "out"
}
},
"outputs": {
@ -677,6 +677,9 @@
"scope": "GlobalVariable",
"type": "variable",
"name": "\"gBlenderRinseMode\""
},
"in": {
"type": "powerrail"
}
},
"outputs": {}
@ -714,18 +717,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
},
"in": {
"uid": "23",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
}
},
"outputs": {
@ -748,18 +751,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
},
"in": {
"uid": "25",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_uid": "31",
"source_instruction_type": "O",
"source_pin": "out"
}
},
"outputs": {
@ -782,18 +785,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
},
"in": {
"uid": "27",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_uid": "31",
"source_instruction_type": "O",
"source_pin": "out"
}
},
"outputs": {
@ -872,17 +875,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
}
},
"outputs": {
@ -913,14 +916,14 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "powerrail"
},
"in": {
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
},
"en": {
"type": "powerrail"
}
},
"outputs": {
@ -950,17 +953,17 @@
"datatype": "TypedConstant",
"value": "DINT#60"
},
"in1": {
"uid": "23",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_sec\""
},
"en": {
"type": "connection",
"source_instruction_type": "Convert",
"source_instruction_uid": "35",
"source_pin": "eno"
},
"in1": {
"uid": "23",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_sec\""
}
},
"outputs": {
@ -1074,17 +1077,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "30",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "39",
"source_pin": "out"
},
"in1": {
"uid": "30",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
}
},
"outputs": {
@ -1110,6 +1113,12 @@
"scope": "GlobalVariable",
"type": "variable",
"name": "\"M19012\""
},
"in": {
"type": "connection",
"source_instruction_type": "Eq",
"source_instruction_uid": "37",
"source_pin": "out"
}
},
"outputs": {}
@ -1172,17 +1181,17 @@
},
"negated_pins": {},
"inputs": {
"in": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "32",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
}
},
"outputs": {
@ -1212,17 +1221,17 @@
"datatype": "TypedConstant",
"value": "DINT#60"
},
"in1": {
"uid": "24",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_min\""
},
"en": {
"type": "connection",
"source_instruction_type": "Convert",
"source_instruction_uid": "33",
"source_pin": "eno"
},
"in1": {
"uid": "24",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_min\""
}
},
"outputs": {
@ -1292,17 +1301,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "29",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
},
"en": {
"type": "connection",
"source_instruction_type": "Eq",
"source_instruction_uid": "35",
"source_pin": "out"
},
"in1": {
"uid": "29",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
}
},
"outputs": {
@ -1332,14 +1341,14 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "powerrail"
},
"in": {
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
},
"en": {
"type": "powerrail"
}
},
"outputs": {

View File

@ -111,17 +111,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gSLIM_Sec\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gSLIM_Sec\""
}
},
"outputs": {
@ -172,18 +172,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_pin": "out"
}
},
"outputs": {
@ -265,17 +265,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
}
},
"outputs": {
@ -385,18 +385,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
}
},
"outputs": {
@ -429,17 +429,17 @@
"datatype": "Int",
"value": 1
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "24",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
},
"en": {
"type": "connection",
"source_instruction_uid": "27",
"source_instruction_type": "Contact",
"source_pin": "out"
}
},
"outputs": {
@ -550,18 +550,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
}
},
"outputs": {
@ -594,17 +594,17 @@
"datatype": "Int",
"value": 1
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
},
"in1": {
"uid": "24",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gProdHour\""
},
"en": {
"type": "connection",
"source_instruction_uid": "30",
"source_instruction_type": "Contact",
"source_pin": "out"
}
},
"outputs": {
@ -637,17 +637,17 @@
"datatype": "Int",
"value": 1
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "30",
"source_pin": "out"
},
"in1": {
"uid": "27",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gBlendingMaintHour\""
},
"en": {
"type": "connection",
"source_instruction_uid": "30",
"source_instruction_type": "Contact",
"source_pin": "out"
}
},
"outputs": {
@ -702,6 +702,9 @@
"scope": "GlobalVariable",
"type": "variable",
"name": "\"gBlenderRinseMode\""
},
"in": {
"type": "powerrail"
}
},
"outputs": {},
@ -741,18 +744,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
},
"in": {
"uid": "23",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
}
},
"outputs": {
@ -777,18 +780,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
},
"in": {
"uid": "25",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_uid": "31",
"source_instruction_type": "O",
"source_pin": "out"
}
},
"outputs": {
@ -813,18 +816,18 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "connection",
"source_instruction_type": "O",
"source_instruction_uid": "31",
"source_pin": "out"
},
"in": {
"uid": "27",
"scope": "LiteralConstant",
"type": "constant",
"datatype": "Int",
"value": 0
},
"en": {
"type": "connection",
"source_instruction_uid": "31",
"source_instruction_type": "O",
"source_pin": "out"
}
},
"outputs": {
@ -907,17 +910,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "27",
"source_pin": "out"
},
"in1": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
}
},
"outputs": {
@ -949,14 +952,14 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "powerrail"
},
"in": {
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
},
"en": {
"type": "powerrail"
}
},
"outputs": {
@ -987,17 +990,17 @@
"datatype": "TypedConstant",
"value": "DINT#60"
},
"in1": {
"uid": "23",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_sec\""
},
"en": {
"type": "connection",
"source_instruction_type": "Convert",
"source_instruction_uid": "35",
"source_pin": "eno"
},
"in1": {
"uid": "23",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_sec\""
}
},
"outputs": {
@ -1115,17 +1118,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "30",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "39",
"source_pin": "out"
},
"in1": {
"uid": "30",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
}
},
"outputs": {
@ -1143,7 +1146,7 @@
{
"instruction_uid": "41",
"uid": "41",
"type": "PBox",
"type": "PBox_scl",
"template_values": {},
"negated_pins": {},
"inputs": {
@ -1152,14 +1155,22 @@
"scope": "GlobalVariable",
"type": "variable",
"name": "\"M19012\""
},
"in": {
"type": "connection",
"source_instruction_type": "Eq",
"source_instruction_uid": "37",
"source_pin": "out"
}
},
"outputs": {}
"outputs": {},
"_edge_mem_update_scl": "\"M19012\" := (\"MOD60\" = DINT#0);",
"scl": "// Logic moved to Coil 42"
},
{
"instruction_uid": "42",
"uid": "42",
"type": "Coil",
"type": "Coil_scl",
"template_values": {},
"negated_pins": {},
"inputs": {
@ -1176,7 +1187,8 @@
"source_pin": "out"
}
},
"outputs": {}
"outputs": {},
"scl": "\"mRunMin\" := (\"MOD60\" = DINT#0) AND NOT \"M19012\";\\n\"M19012\" := (\"MOD60\" = DINT#0); // P_TRIG((\"MOD60\" = DINT#0)) (Mem update handled by consumer)"
}
]
},
@ -1215,17 +1227,17 @@
},
"negated_pins": {},
"inputs": {
"in": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
},
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "32",
"source_pin": "out"
},
"in": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMinutes\""
}
},
"outputs": {
@ -1256,17 +1268,17 @@
"datatype": "TypedConstant",
"value": "DINT#60"
},
"in1": {
"uid": "24",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_min\""
},
"en": {
"type": "connection",
"source_instruction_type": "Convert",
"source_instruction_uid": "33",
"source_pin": "eno"
},
"in1": {
"uid": "24",
"scope": "LocalVariable",
"type": "variable",
"name": "\"I_DIRunning_min\""
}
},
"outputs": {
@ -1338,17 +1350,17 @@
"datatype": "Int",
"value": 1
},
"in1": {
"uid": "29",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
},
"en": {
"type": "connection",
"source_instruction_type": "Eq",
"source_instruction_uid": "35",
"source_pin": "out"
},
"in1": {
"uid": "29",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
}
},
"outputs": {
@ -1379,14 +1391,14 @@
},
"negated_pins": {},
"inputs": {
"en": {
"type": "powerrail"
},
"in": {
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
},
"en": {
"type": "powerrail"
}
},
"outputs": {

View File

@ -109,6 +109,8 @@ BEGIN
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;
// Logic moved to Coil 42
"mRunMin" := ("MOD60" = DINT#0) AND NOT "M19012";\n"M19012" := ("MOD60" = DINT#0); // P_TRIG(("MOD60" = DINT#0)) (Mem update handled by consumer)
// Network 11: Running Hours for Maintenance

View File

@ -7,7 +7,15 @@
<Section Name="Input" />
<Section Name="Output" />
<Section Name="InOut" />
<Section Name="Temp" />
<Section Name="Temp">
<Member Name="All_Auto_RETVAL" Datatype="Int" />
<Member Name="Reset_SP_Word_RETVAL" Datatype="Int" />
<Member Name="mResetWaterTot" Datatype="Bool" />
<Member Name="mResetSyrupTot" Datatype="Bool" />
<Member Name="mResetCO2Tot" Datatype="Bool" />
<Member Name="mResetProductTot" Datatype="Bool" />
<Member Name="Block_Move_Err" Datatype="Int" />
</Section>
<Section Name="Constant" />
<Section Name="Return">
<Member Name="Ret_Val" Datatype="Void" />
@ -69,54 +77,7 @@
</MultilingualText>
<SW.Blocks.CompileUnit ID="9" CompositionName="CompileUnits">
<AttributeList>
<NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
<Parts>
<Access Scope="GlobalVariable" UId="21">
<Symbol>
<Component Name="Clock_10Hz" />
</Symbol>
</Access>
<Access Scope="GlobalVariable" UId="22">
<Symbol>
<Component Name="M19001" />
</Symbol>
</Access>
<Access Scope="GlobalVariable" UId="23">
<Symbol>
<Component Name="Clock_5Hz" />
</Symbol>
</Access>
<Part Name="Contact" UId="24" />
<Part Name="PBox" UId="25" />
<Part Name="Coil" UId="26" />
</Parts>
<Wires>
<Wire UId="27">
<Powerrail />
<NameCon UId="24" Name="in" />
</Wire>
<Wire UId="28">
<IdentCon UId="21" />
<NameCon UId="24" Name="operand" />
</Wire>
<Wire UId="29">
<NameCon UId="24" Name="out" />
<NameCon UId="25" Name="in" />
</Wire>
<Wire UId="30">
<IdentCon UId="22" />
<NameCon UId="25" Name="bit" />
</Wire>
<Wire UId="31">
<NameCon UId="25" Name="out" />
<NameCon UId="26" Name="in" />
</Wire>
<Wire UId="32">
<IdentCon UId="23" />
<NameCon UId="26" Name="operand" />
</Wire>
</Wires>
</FlgNet></NetworkSource>
<NetworkSource />
<ProgrammingLanguage>LAD</ProgrammingLanguage>
</AttributeList>
<ObjectList>
@ -171,7 +132,7 @@
<MultilingualTextItem ID="13" CompositionName="Items">
<AttributeList>
<Culture>it-IT</Culture>
<Text>Clock Bit</Text>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="14" CompositionName="Items">
@ -220,47 +181,55 @@
<Parts>
<Access Scope="GlobalVariable" UId="21">
<Symbol>
<Component Name="Clock_10Hz" />
<Component Name="AUX FALSE" />
</Symbol>
</Access>
<Access Scope="GlobalVariable" UId="22">
<Symbol>
<Component Name="M19001" />
<Component Name="HMI_PID" />
<Component Name="PPM303" />
</Symbol>
</Access>
<Access Scope="GlobalVariable" UId="23">
<Access Scope="LocalVariable" UId="23">
<Symbol>
<Component Name="Clock_5Hz" />
<Component Name="Block_Move_Err" />
</Symbol>
</Access>
<Part Name="Contact" UId="24" />
<Part Name="NBox" UId="25" />
<Part Name="Coil" UId="26" />
<Access Scope="GlobalVariable" UId="24">
<Symbol>
<Component Name="Filler_Head_Variables" />
<Component Name="FillerHead" />
</Symbol>
</Access>
<Part Name="Contact" UId="25" />
<Part Name="BLKMOV" Version="1.1" UId="26">
<TemplateValue Name="blk_type" Type="Type">Variant</TemplateValue>
</Part>
</Parts>
<Wires>
<Wire UId="27">
<Powerrail />
<NameCon UId="24" Name="in" />
<NameCon UId="25" Name="in" />
</Wire>
<Wire UId="28">
<IdentCon UId="21" />
<NameCon UId="24" Name="operand" />
<NameCon UId="25" Name="operand" />
</Wire>
<Wire UId="29">
<NameCon UId="24" Name="out" />
<NameCon UId="25" Name="in" />
<NameCon UId="25" Name="out" />
<NameCon UId="26" Name="en" />
</Wire>
<Wire UId="30">
<IdentCon UId="22" />
<NameCon UId="25" Name="bit" />
<NameCon UId="26" Name="SRCBLK" />
</Wire>
<Wire UId="31">
<NameCon UId="25" Name="out" />
<NameCon UId="26" Name="in" />
<NameCon UId="26" Name="RET_VAL" />
<IdentCon UId="23" />
</Wire>
<Wire UId="32">
<IdentCon UId="23" />
<NameCon UId="26" Name="operand" />
<NameCon UId="26" Name="DSTBLK" />
<IdentCon UId="24" />
</Wire>
</Wires>
</FlgNet></NetworkSource>
@ -318,7 +287,7 @@
<MultilingualTextItem ID="24" CompositionName="Items">
<AttributeList>
<Culture>it-IT</Culture>
<Text>Clock Bit</Text>
<Text>Filler Head</Text>
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="25" CompositionName="Items">
@ -361,145 +330,45 @@
</MultilingualText>
</ObjectList>
</SW.Blocks.CompileUnit>
<SW.Blocks.CompileUnit ID="2B" CompositionName="CompileUnits">
<AttributeList>
<NetworkSource />
<ProgrammingLanguage>LAD</ProgrammingLanguage>
</AttributeList>
<MultilingualText ID="2B" CompositionName="Title">
<ObjectList>
<MultilingualText ID="2C" CompositionName="Comment">
<ObjectList>
<MultilingualTextItem ID="2D" CompositionName="Items">
<AttributeList>
<Culture>it-IT</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="2E" CompositionName="Items">
<AttributeList>
<Culture>de-DE</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="2F" CompositionName="Items">
<AttributeList>
<Culture>en-US</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="30" CompositionName="Items">
<AttributeList>
<Culture>es-ES</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="31" CompositionName="Items">
<AttributeList>
<Culture>fr-FR</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="32" CompositionName="Items">
<AttributeList>
<Culture>zh-CN</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="33" CompositionName="Items">
<AttributeList>
<Culture>ja-JP</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
</ObjectList>
</MultilingualText>
<MultilingualText ID="34" CompositionName="Title">
<ObjectList>
<MultilingualTextItem ID="35" CompositionName="Items">
<AttributeList>
<Culture>it-IT</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="36" CompositionName="Items">
<AttributeList>
<Culture>de-DE</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="37" CompositionName="Items">
<AttributeList>
<Culture>en-US</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="38" CompositionName="Items">
<AttributeList>
<Culture>es-ES</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="39" CompositionName="Items">
<AttributeList>
<Culture>fr-FR</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="3A" CompositionName="Items">
<AttributeList>
<Culture>zh-CN</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="3B" CompositionName="Items">
<AttributeList>
<Culture>ja-JP</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
</ObjectList>
</MultilingualText>
</ObjectList>
</SW.Blocks.CompileUnit>
<MultilingualText ID="3C" CompositionName="Title">
<ObjectList>
<MultilingualTextItem ID="3D" CompositionName="Items">
<MultilingualTextItem ID="2C" CompositionName="Items">
<AttributeList>
<Culture>it-IT</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="3E" CompositionName="Items">
<MultilingualTextItem ID="2D" CompositionName="Items">
<AttributeList>
<Culture>de-DE</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="3F" CompositionName="Items">
<MultilingualTextItem ID="2E" CompositionName="Items">
<AttributeList>
<Culture>en-US</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="40" CompositionName="Items">
<MultilingualTextItem ID="2F" CompositionName="Items">
<AttributeList>
<Culture>es-ES</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="41" CompositionName="Items">
<MultilingualTextItem ID="30" CompositionName="Items">
<AttributeList>
<Culture>fr-FR</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="42" CompositionName="Items">
<MultilingualTextItem ID="31" CompositionName="Items">
<AttributeList>
<Culture>zh-CN</Culture>
<Text />
</AttributeList>
</MultilingualTextItem>
<MultilingualTextItem ID="43" CompositionName="Items">
<MultilingualTextItem ID="32" CompositionName="Items">
<AttributeList>
<Culture>ja-JP</Culture>
<Text />

View File

@ -4,6 +4,36 @@
"language": "LAD",
"block_comment": "",
"interface": {
"Temp": [
{
"name": "All_Auto_RETVAL",
"datatype": "Int"
},
{
"name": "Reset_SP_Word_RETVAL",
"datatype": "Int"
},
{
"name": "mResetWaterTot",
"datatype": "Bool"
},
{
"name": "mResetSyrupTot",
"datatype": "Bool"
},
{
"name": "mResetCO2Tot",
"datatype": "Bool"
},
{
"name": "mResetProductTot",
"datatype": "Bool"
},
{
"name": "Block_Move_Err",
"datatype": "Int"
}
],
"Return": [
{
"name": "Ret_Val",
@ -12,84 +42,14 @@
]
},
"networks": [
{
"id": "9",
"title": "Clock Bit",
"comment": "",
"logic": [
{
"instruction_uid": "24",
"uid": "24",
"type": "Contact",
"template_values": {},
"negated_pins": {},
"inputs": {
"operand": {
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_10Hz\""
},
"in": {
"type": "powerrail"
}
},
"outputs": {}
},
{
"instruction_uid": "25",
"uid": "25",
"type": "PBox",
"template_values": {},
"negated_pins": {},
"inputs": {
"in": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_pin": "out"
},
"bit": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"M19001\""
}
},
"outputs": {}
},
{
"instruction_uid": "26",
"uid": "26",
"type": "Coil",
"template_values": {},
"negated_pins": {},
"inputs": {
"operand": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_5Hz\""
},
"in": {
"type": "connection",
"source_instruction_type": "PBox",
"source_instruction_uid": "25",
"source_pin": "out"
}
},
"outputs": {}
}
]
},
{
"id": "1A",
"title": "Clock Bit",
"title": "Filler Head",
"comment": "",
"logic": [
{
"instruction_uid": "24",
"uid": "24",
"instruction_uid": "25",
"uid": "25",
"type": "Contact",
"template_values": {},
"negated_pins": {},
@ -98,7 +58,7 @@
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_10Hz\""
"name": "\"AUX FALSE\""
},
"in": {
"type": "powerrail"
@ -107,48 +67,45 @@
"outputs": {}
},
{
"instruction_uid": "25",
"uid": "25",
"type": "NBox",
"template_values": {},
"instruction_uid": "26",
"uid": "26",
"type": "BLKMOV",
"template_values": {
"blk_type": "Type"
},
"negated_pins": {},
"inputs": {
"in": {
"en": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_instruction_uid": "25",
"source_pin": "out"
},
"bit": {
"SRCBLK": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"M19001\""
"name": "\"HMI_PID\".\"PPM303\""
}
},
"outputs": {}
},
{
"instruction_uid": "26",
"uid": "26",
"type": "Coil",
"template_values": {},
"negated_pins": {},
"inputs": {
"operand": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_5Hz\""
},
"in": {
"type": "connection",
"source_instruction_type": "NBox",
"source_instruction_uid": "25",
"source_pin": "out"
}
},
"outputs": {}
"outputs": {
"RET_VAL": [
{
"uid": "23",
"scope": "LocalVariable",
"type": "variable",
"name": "\"Block_Move_Err\""
}
],
"DSTBLK": [
{
"uid": "24",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Filler_Head_Variables\".\"FillerHead\""
}
]
}
}
]
}

View File

@ -4,6 +4,36 @@
"language": "LAD",
"block_comment": "",
"interface": {
"Temp": [
{
"name": "All_Auto_RETVAL",
"datatype": "Int"
},
{
"name": "Reset_SP_Word_RETVAL",
"datatype": "Int"
},
{
"name": "mResetWaterTot",
"datatype": "Bool"
},
{
"name": "mResetSyrupTot",
"datatype": "Bool"
},
{
"name": "mResetCO2Tot",
"datatype": "Bool"
},
{
"name": "mResetProductTot",
"datatype": "Bool"
},
{
"name": "Block_Move_Err",
"datatype": "Int"
}
],
"Return": [
{
"name": "Ret_Val",
@ -12,88 +42,14 @@
]
},
"networks": [
{
"id": "9",
"title": "Clock Bit",
"comment": "",
"logic": [
{
"instruction_uid": "24",
"uid": "24",
"type": "Contact_scl",
"template_values": {},
"negated_pins": {},
"inputs": {
"operand": {
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_10Hz\""
},
"in": {
"type": "powerrail"
}
},
"outputs": {},
"scl": "// RLO: \"Clock_10Hz\""
},
{
"instruction_uid": "25",
"uid": "25",
"type": "PBox_scl",
"template_values": {},
"negated_pins": {},
"inputs": {
"in": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_pin": "out"
},
"bit": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"M19001\""
}
},
"outputs": {},
"_edge_mem_update_scl": "\"M19001\" := \"Clock_10Hz\";",
"scl": "// Logic moved to Coil 26"
},
{
"instruction_uid": "26",
"uid": "26",
"type": "Coil_scl",
"template_values": {},
"negated_pins": {},
"inputs": {
"operand": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_5Hz\""
},
"in": {
"type": "connection",
"source_instruction_type": "PBox",
"source_instruction_uid": "25",
"source_pin": "out"
}
},
"outputs": {},
"scl": "\"Clock_5Hz\" := \"Clock_10Hz\" AND NOT \"M19001\";\\n\"M19001\" := \"Clock_10Hz\"; // P_TRIG(\"Clock_10Hz\") (Mem update handled by consumer)"
}
]
},
{
"id": "1A",
"title": "Clock Bit",
"title": "Filler Head",
"comment": "",
"logic": [
{
"instruction_uid": "24",
"uid": "24",
"instruction_uid": "25",
"uid": "25",
"type": "Contact_scl",
"template_values": {},
"negated_pins": {},
@ -102,61 +58,55 @@
"uid": "21",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_10Hz\""
"name": "\"AUX FALSE\""
},
"in": {
"type": "powerrail"
}
},
"outputs": {},
"scl": "// RLO: \"Clock_10Hz\""
},
{
"instruction_uid": "25",
"uid": "25",
"type": "NBox_scl",
"template_values": {},
"negated_pins": {},
"inputs": {
"in": {
"type": "connection",
"source_instruction_type": "Contact",
"source_instruction_uid": "24",
"source_pin": "out"
},
"bit": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"M19001\""
}
},
"outputs": {},
"_edge_mem_update_scl": "\"M19001\" := \"Clock_10Hz\";",
"scl": "// Logic moved to Coil 26"
"scl": "// RLO: \"AUX FALSE\""
},
{
"instruction_uid": "26",
"uid": "26",
"type": "Coil_scl",
"template_values": {},
"type": "BLKMOV",
"template_values": {
"blk_type": "Type"
},
"negated_pins": {},
"inputs": {
"operand": {
"uid": "23",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Clock_5Hz\""
},
"in": {
"en": {
"type": "connection",
"source_instruction_type": "NBox",
"source_instruction_type": "Contact",
"source_instruction_uid": "25",
"source_pin": "out"
},
"SRCBLK": {
"uid": "22",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"HMI_PID\".\"PPM303\""
}
},
"outputs": {},
"scl": "\"Clock_5Hz\" := NOT \"Clock_10Hz\" AND \"M19001\";\\n\"M19001\" := \"Clock_10Hz\"; // N_TRIG(\"Clock_10Hz\") (Mem update handled by consumer)"
"outputs": {
"RET_VAL": [
{
"uid": "23",
"scope": "LocalVariable",
"type": "variable",
"name": "\"Block_Move_Err\""
}
],
"DSTBLK": [
{
"uid": "24",
"scope": "GlobalVariable",
"type": "variable",
"name": "\"Filler_Head_Variables\".\"FillerHead\""
}
]
}
}
]
}

View File

@ -16,20 +16,19 @@ VAR_IN_OUT
END_VAR
VAR_TEMP
All_Auto_RETVAL : Int;
Reset_SP_Word_RETVAL : Int;
mResetWaterTot : Bool;
mResetSyrupTot : Bool;
mResetCO2Tot : Bool;
mResetProductTot : Bool;
Block_Move_Err : Int;
END_VAR
BEGIN
// Network 1: Clock Bit
// Network 1: Filler Head
// RLO: "Clock_10Hz"
// Logic moved to Coil 26
"Clock_5Hz" := "Clock_10Hz" AND NOT "M19001";\n"M19001" := "Clock_10Hz"; // P_TRIG("Clock_10Hz") (Mem update handled by consumer)
// Network 2: Clock Bit
// RLO: "Clock_10Hz"
// Logic moved to Coil 26
"Clock_5Hz" := NOT "Clock_10Hz" AND "M19001";\n"M19001" := "Clock_10Hz"; // N_TRIG("Clock_10Hz") (Mem update handled by consumer)
// RLO: "AUX FALSE"
END_FUNCTION_BLOCK

View File

@ -140,9 +140,173 @@ def parse_call(call_element):
if instance_scope: call_data["instance_scope"] = instance_scope
return call_data
# --- Función parse_network con XPath corregido para Title/Comment ---
# --- Función parse_network MODIFICADA (maneja multi-destino en Wire) ---
def parse_network(network_element):
"""
Parsea una red, extrae lógica y añade conexiones EN implícitas.
Maneja wires con múltiples destinos.
"""
if network_element is None:
return {"id": "ERROR", "title": "Invalid Network Element", "comment": "", "logic": [], "error": "Input element was None"}
network_id = network_element.get("ID")
# --- Extracción Título/Comentario (sin cambios respecto a la última versión) ---
title_element = network_element.xpath(
".//*[local-name()='MultilingualText'][@CompositionName='Title']"
)
network_title = get_multilingual_text(title_element[0]) if title_element else f"Network {network_id}"
comment_element = network_element.xpath(
"./*[local-name()='ObjectList']/*[local-name()='MultilingualText'][@CompositionName='Comment']"
)
network_comment = get_multilingual_text(comment_element[0]) if comment_element else ""
flgnet_list = network_element.xpath(".//flg:FlgNet", namespaces=ns)
if not flgnet_list:
# print(f"Advertencia: FlgNet no encontrado en Red ID={network_id}. Puede estar vacía o ser comentario.")
return {"id": network_id, "title": network_title, "comment": network_comment, "logic": [], "error": "FlgNet not found"}
flgnet = flgnet_list[0]
# 1. Parsear Access, Parts y Calls (sin cambios)
access_map = {acc_info["uid"]: acc_info for acc in flgnet.xpath(".//flg:Access", namespaces=ns) if (acc_info := parse_access(acc)) and acc_info['type'] != 'unknown'}
parts_and_calls_map = {}
instruction_elements = flgnet.xpath(".//flg:Part | .//flg:Call", namespaces=ns)
for element in instruction_elements:
parsed_info = None
tag_name = etree.QName(element.tag).localname # Obtener nombre local de la etiqueta
if tag_name == "Part": parsed_info = parse_part(element)
elif tag_name == "Call": parsed_info = parse_call(element)
if parsed_info and "uid" in parsed_info: parts_and_calls_map[parsed_info["uid"]] = parsed_info
else: print(f"Advertencia: Se ignoró un Part/Call inválido en la red {network_id}")
# --- 2. Parsear Wires (MODIFICADO para multi-destino) ---
wire_connections = defaultdict(list) # (dest_uid, dest_pin) -> [(src_uid, src_pin), ...]
source_connections = defaultdict(list) # (src_uid, src_pin) -> [(dest_uid, dest_pin), ...]
eno_outputs = defaultdict(list) # src_uid -> [(dest_uid, dest_pin), ...] (conexiones DESDE eno)
flg_ns_uri = ns["flg"] # Cache namespace URI
qname_powerrail = etree.QName(flg_ns_uri, "Powerrail")
qname_identcon = etree.QName(flg_ns_uri, "IdentCon")
qname_namecon = etree.QName(flg_ns_uri, "NameCon")
for wire in flgnet.xpath(".//flg:Wire", namespaces=ns):
children = wire.getchildren()
if len(children) < 2: continue # Ignorar wires sin fuente y al menos un destino
source_elem = children[0]
source_uid, source_pin = None, None
# Determinar fuente
if source_elem.tag == qname_powerrail: source_uid, source_pin = "POWERRAIL", "out"
elif source_elem.tag == qname_identcon: source_uid, source_pin = source_elem.get("UId"), "value" # Acceso a variable/constante
elif source_elem.tag == qname_namecon: source_uid, source_pin = source_elem.get("UId"), source_elem.get("Name") # Salida de instrucción
if source_uid is None: continue # No se pudo determinar la fuente
source_info = (source_uid, source_pin) # Par de fuente
# Iterar sobre TODOS los posibles destinos (desde el segundo hijo en adelante)
for dest_elem in children[1:]:
dest_uid, dest_pin = None, None
# Determinar destino
if dest_elem.tag == qname_identcon: dest_uid, dest_pin = dest_elem.get("UId"), "value" # Entrada a variable/constante (Coil, etc.)
elif dest_elem.tag == qname_namecon: dest_uid, dest_pin = dest_elem.get("UId"), dest_elem.get("Name") # Entrada a instrucción
# Guardar conexiones si son válidas
if dest_uid is not None and dest_pin is not None:
# Mapa de Conexiones (Destino -> [Fuentes])
dest_key = (dest_uid, dest_pin)
if source_info not in wire_connections[dest_key]:
wire_connections[dest_key].append(source_info)
# Mapa de Fuentes (Fuente -> [Destinos])
source_key = (source_uid, source_pin)
dest_info = (dest_uid, dest_pin)
if dest_info not in source_connections[source_key]:
source_connections[source_key].append(dest_info)
# Registrar conexiones que SALEN de un pin 'eno'
if source_pin == "eno" and source_uid in parts_and_calls_map:
if dest_info not in eno_outputs[source_uid]:
eno_outputs[source_uid].append(dest_info)
# else: # Debug opcional si un elemento no es destino válido
# print(f"Advertencia: Elemento en Wire {wire.get('UId')} no es destino válido: {etree.tostring(dest_elem)}")
# --- FIN MODIFICACIÓN Wire ---
# 3. Construcción Lógica Inicial (sin cambios)
all_logic_steps = {}
functional_block_types = ['Move', 'Add', 'Sub', 'Mul', 'Div', 'Mod', 'Convert', 'Call', 'Se', 'Sd', 'BLKMOV']
rlo_generators = ['Contact', 'O', 'Eq', 'Ne', 'Gt', 'Lt', 'Ge', 'Le', 'And', 'Xor', 'PBox', 'NBox']
for instruction_uid, instruction_info in parts_and_calls_map.items():
instruction_repr = {"instruction_uid": instruction_uid, **instruction_info}; instruction_repr["inputs"] = {}; instruction_repr["outputs"] = {}
possible_input_pins = set(['en', 'in', 'in1', 'in2', 'in3', 'in4', 's', 'r', 'clk', 'cu', 'cd', 'ld', 'pv', 'tv', 'bit', 'operand', 'pre', 'SRCBLK'])
for dest_pin_name in possible_input_pins:
dest_key = (instruction_uid, dest_pin_name)
if dest_key in wire_connections:
sources_list = wire_connections[dest_key]; input_sources_repr = []
for source_uid, source_pin in sources_list:
if source_uid == "POWERRAIL": input_sources_repr.append({"type": "powerrail"})
elif source_uid in access_map: input_sources_repr.append(access_map[source_uid])
elif source_uid in parts_and_calls_map: input_sources_repr.append({"type": "connection", "source_instruction_type": parts_and_calls_map[source_uid]["type"], "source_instruction_uid": source_uid, "source_pin": source_pin})
else: input_sources_repr.append({"type": "unknown_source", "uid": source_uid})
if len(input_sources_repr) == 1: instruction_repr["inputs"][dest_pin_name] = input_sources_repr[0]
elif len(input_sources_repr) > 1: instruction_repr["inputs"][dest_pin_name] = input_sources_repr
possible_output_pins = set(['out', 'out1', 'Q', 'eno', 'RET_VAL', 'DSTBLK', 'q', 'rt', 'rtbcd', 'cv', 'cvbcd'])
for source_pin_name in possible_output_pins:
source_key = (instruction_uid, source_pin_name)
if source_key in source_connections:
for dest_uid, dest_pin in source_connections[source_key]:
if dest_uid in access_map:
if source_pin_name not in instruction_repr["outputs"]: instruction_repr["outputs"][source_pin_name] = []
if access_map[dest_uid] not in instruction_repr["outputs"][source_pin_name]: instruction_repr["outputs"][source_pin_name].append(access_map[dest_uid])
all_logic_steps[instruction_uid] = instruction_repr
# 4. Inferencia EN (sin cambios)
processed_blocks_en_inference = set(); something_changed = True; inference_passes = 0; max_inference_passes = len(all_logic_steps) + 5
try: sorted_uids_for_en = sorted(all_logic_steps.keys(), key=lambda x: int(x) if x.isdigit() else float('inf'))
except ValueError: sorted_uids_for_en = sorted(all_logic_steps.keys())
ordered_logic_list_for_en = [all_logic_steps[uid] for uid in sorted_uids_for_en if uid in all_logic_steps]
while something_changed and inference_passes < max_inference_passes:
something_changed = False; inference_passes += 1
for i, instruction in enumerate(ordered_logic_list_for_en):
part_uid = instruction["instruction_uid"]; part_type_original = instruction["type"].replace('_scl', '').replace('_error', '')
if (part_type_original in functional_block_types and "en" not in instruction["inputs"] and part_uid not in processed_blocks_en_inference):
inferred_en_source = None
if i > 0:
for j in range(i - 1, -1, -1):
prev_instr = ordered_logic_list_for_en[j]; prev_uid = prev_instr["instruction_uid"]; prev_type_original = prev_instr["type"].replace('_scl', '').replace('_error', '')
if prev_type_original in rlo_generators: inferred_en_source = {"type": "connection", "source_instruction_uid": prev_uid, "source_instruction_type": prev_type_original, "source_pin": "out"}; break
elif prev_type_original in functional_block_types:
source_key_eno = (prev_uid, "eno")
if source_key_eno in source_connections: inferred_en_source = {"type": "connection", "source_instruction_uid": prev_uid, "source_instruction_type": prev_type_original, "source_pin": "eno"}; break
else: continue
elif prev_type_original in ['Coil', 'SCoil', 'RCoil', 'SetCoil', 'ResetCoil', 'SdCoil']: break
if inferred_en_source: all_logic_steps[part_uid]["inputs"]["en"] = inferred_en_source; processed_blocks_en_inference.add(part_uid); something_changed = True
# 5. Añadir lógica ENO interesante (sin cambios)
for source_instr_uid, eno_destinations in eno_outputs.items():
if source_instr_uid not in all_logic_steps: continue
interesting_eno_logic = []
for dest_uid, dest_pin in eno_destinations:
is_direct_en_connection = False
if dest_uid in parts_and_calls_map and dest_pin == 'en':
try:
source_idx = sorted_uids_for_en.index(source_instr_uid); dest_idx = sorted_uids_for_en.index(dest_uid)
if dest_idx == source_idx + 1 and parts_and_calls_map[dest_uid]['type'] in functional_block_types: is_direct_en_connection = True
except ValueError: pass
if not is_direct_en_connection:
target_info = {"target_pin": dest_pin}
if dest_uid in parts_and_calls_map: target_info.update({"target_type": "instruction", "target_uid": dest_uid, "target_name": parts_and_calls_map[dest_uid].get("name", parts_and_calls_map[dest_uid].get("type"))})
elif dest_uid in access_map: target_info.update({"target_type": "operand", "target_details": access_map[dest_uid]})
else: target_info.update({"target_type": "unknown", "target_uid": dest_uid})
interesting_eno_logic.append(target_info)
if interesting_eno_logic: all_logic_steps[source_instr_uid]["eno_logic"] = interesting_eno_logic
# 6. Ordenar y Devolver (sin cambios)
network_logic_final = [all_logic_steps[uid] for uid in sorted_uids_for_en if uid in all_logic_steps]
return {"id": network_id, "title": network_title, "comment": network_comment, "logic": network_logic_final}
"""
Parsea una red, extrae lógica y añade conexiones EN implícitas.
"""
@ -274,7 +438,6 @@ def parse_network(network_element):
network_logic_final = [all_logic_steps[uid] for uid in sorted_uids_for_en if uid in all_logic_steps]
return {"id": network_id, "title": network_title, "comment": network_comment, "logic": network_logic_final}
# --- Función Principal convert_xml_to_json (sin cambios en su flujo general) ---
def convert_xml_to_json(xml_filepath, json_filepath):
print(f"Iniciando conversión de '{xml_filepath}' a '{json_filepath}'...")
@ -357,7 +520,7 @@ def convert_xml_to_json(xml_filepath, json_filepath):
# --- Punto de Entrada Principal ---
if __name__ == "__main__":
xml_filename_base = "BlenderRun_ProdTime"
xml_filename_base = "TestLAD"
xml_file = f"{xml_filename_base}.xml"
json_file = f"{xml_filename_base}_simplified.json"
convert_xml_to_json(xml_file, json_file)

View File

@ -258,6 +258,135 @@ def process_contact(instruction, network_id, scl_map, access_map):
instruction["type"] = instr_type + SCL_SUFFIX
return True
# --- process_edge_detector MODIFICADA ---
def process_edge_detector(instruction, network_id, scl_map, access_map):
"""Genera SCL para PBox (P_TRIG) o NBox (N_TRIG).
Guarda la expresión del pulso en scl_map['out'] y la actualización
de memoria en un campo temporal '_edge_mem_update_scl'.
El campo 'scl' principal se deja casi vacío/comentario.
Usa el nombre de memoria original sin renombrar.
"""
instr_uid = instruction["instruction_uid"]
instr_type_original = instruction["type"] # PBox o NBox
if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
return False # Ya procesado o error
# 1. Obtener CLK y MemBit original
clk_input = instruction["inputs"].get("in")
mem_bit_input = instruction["inputs"].get("bit")
clk_scl = get_scl_representation(clk_input, network_id, scl_map, access_map)
mem_bit_scl_original = get_scl_representation(mem_bit_input, network_id, scl_map, access_map) # Ej: "M19001"
# 2. Verificar dependencias y tipo de MemBit
if clk_scl is None: return False
if mem_bit_scl_original is None:
instruction["scl"] = f"// ERROR: {instr_type_original} {instr_uid} MemBit no resuelto."
instruction["type"] = instr_type_original + "_error"
return True
if not (mem_bit_input and mem_bit_input.get("type") == "variable"):
instruction["scl"] = f"// ERROR: {instr_type_original} {instr_uid} 'bit' no es variable."
instruction["type"] = instr_type_original + "_error"
return True
# 3. Formatear CLK (usa memoria original)
clk_scl_formatted = clk_scl
if clk_scl not in ["TRUE", "FALSE"] and \
(' ' in clk_scl or 'AND' in clk_scl or 'OR' in clk_scl or ':=' in clk_scl) and \
not (clk_scl.startswith('(') and clk_scl.endswith(')')):
clk_scl_formatted = f"({clk_scl})"
# 4. Generar Lógica SCL del *pulso*
result_pulse_expression = "FALSE"
scl_comment = ""
if instr_type_original == "PBox": # P_TRIG
result_pulse_expression = f"{clk_scl_formatted} AND NOT {mem_bit_scl_original}"
scl_comment = f"// P_TRIG({clk_scl_formatted})"
elif instr_type_original == "NBox": # N_TRIG
result_pulse_expression = f"NOT {clk_scl_formatted} AND {mem_bit_scl_original}"
scl_comment = f"// N_TRIG({clk_scl_formatted})"
else: # Error
instruction["scl"] = f"// ERROR: Tipo de flanco inesperado {instr_type_original}"
instruction["type"] = instr_type_original + "_error"
return True
# 5. Generar la actualización del bit de memoria
scl_mem_update = f"{mem_bit_scl_original} := {clk_scl_formatted};"
# 6. Almacenar Resultados
map_key_out = (network_id, instr_uid, "out")
scl_map[map_key_out] = result_pulse_expression # Guardar EXPRESIÓN del pulso
instruction['_edge_mem_update_scl'] = f"{scl_mem_update} {scl_comment}" # Guardar UPDATE + Comentario en campo temporal
instruction['scl'] = f"// {instr_type_original} Logic moved to consumer Coil" # Dejar SCL principal vacío/comentario
instruction["type"] = instr_type_original + SCL_SUFFIX
# 7. Propagar ENO
map_key_eno = (network_id, instr_uid, "eno")
scl_map[map_key_eno] = clk_scl
return True
# --- process_coil MODIFICADA (con \n correcto) ---
def process_coil(instruction, network_id, scl_map, access_map):
"""Genera la asignación para Coil. Si la entrada viene de PBox/NBox,
añade la actualización de memoria del flanco DESPUÉS de la asignación."""
instr_uid = instruction["instruction_uid"]
instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
return False
coil_input_info = instruction["inputs"].get("in")
operand_info = instruction["inputs"].get("operand")
in_rlo_scl = get_scl_representation(coil_input_info, network_id, scl_map, access_map)
operand_scl = get_scl_representation(operand_info, network_id, scl_map, access_map)
if in_rlo_scl is None or operand_scl is None: return False
if not (operand_info and operand_info.get("type") == "variable"):
instruction["scl"] = f"// ERROR: Coil {instr_uid} operando no es variable o falta info"
instruction["type"] = instr_type + "_error"
return True
operand_scl_formatted = format_variable_name(operand_scl)
if in_rlo_scl == "(TRUE)": in_rlo_scl = "TRUE"
elif in_rlo_scl == "(FALSE)": in_rlo_scl = "FALSE"
# Generar la asignación SCL principal de la bobina
scl_assignment = f"{operand_scl_formatted} := {in_rlo_scl};"
scl_final = scl_assignment # Inicializar SCL final
# --- Lógica para añadir actualización de memoria de flancos ---
mem_update_scl_combined = None
if isinstance(coil_input_info, dict) and coil_input_info.get("type") == "connection":
source_uid = coil_input_info.get("source_instruction_uid")
source_pin = coil_input_info.get("source_pin")
# Buscar la instrucción fuente PBox/NBox
source_instruction = None
network_logic = next((net["logic"] for net in data["networks"] if net["id"] == network_id), [])
for instr in network_logic:
if instr.get("instruction_uid") == source_uid:
source_instruction = instr
break
if source_instruction:
source_type = source_instruction.get("type","").replace('_scl','').replace('_error','')
# Si la fuente es PBox o NBox y tiene el campo temporal con la actualización
if source_type in ["PBox", "NBox"] and '_edge_mem_update_scl' in source_instruction:
mem_update_scl_combined = source_instruction.get('_edge_mem_update_scl') # Obtener update+comment
if mem_update_scl_combined:
# Añadir la actualización DESPUÉS de la asignación de la bobina, USANDO \n
scl_final = f"{scl_assignment}\n{mem_update_scl_combined}"
# Marcar la instrucción PBox/NBox para que x3 no escriba su SCL (que ahora está vacío/comentario)
source_instruction['scl'] = f"// Logic moved to Coil {instr_uid}" # Actualizar PBox/NBox SCL
instruction["scl"] = scl_final
instruction["type"] = instr_type + SCL_SUFFIX
return True
def process_eq(instruction, network_id, scl_map, access_map):
instr_uid = instruction["instruction_uid"]
instr_type = instruction["type"]
@ -314,127 +443,6 @@ def process_eq(instruction, network_id, scl_map, access_map):
instruction["type"] = instr_type + SCL_SUFFIX
return True
# --- process_edge_detector MODIFICADA ---
def process_edge_detector(instruction, network_id, scl_map, access_map):
"""Genera SCL para PBox (P_TRIG) o NBox (N_TRIG).
Guarda la expresión del pulso en scl_map['out'] y la actualización
de memoria en un campo temporal '_edge_mem_update_scl'.
El campo 'scl' principal se deja casi vacío.
"""
instr_uid = instruction["instruction_uid"]
instr_type_original = instruction["type"] # PBox o NBox
if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
return False
# 1. Obtener CLK y MemBit original
clk_input = instruction["inputs"].get("in")
mem_bit_input = instruction["inputs"].get("bit")
clk_scl = get_scl_representation(clk_input, network_id, scl_map, access_map)
mem_bit_scl_original = get_scl_representation(mem_bit_input, network_id, scl_map, access_map)
# 2. Verificar dependencias y tipo de MemBit
if clk_scl is None or mem_bit_scl_original is None: return False
if not (mem_bit_input and mem_bit_input.get("type") == "variable"):
instruction["scl"] = f"// ERROR: {instr_type_original} {instr_uid} 'bit' no es variable."
instruction["type"] = instr_type_original + "_error"
return True
# 3. Formatear CLK
clk_scl_formatted = clk_scl
if clk_scl not in ["TRUE", "FALSE"] and \
(' ' in clk_scl or 'AND' in clk_scl or 'OR' in clk_scl or ':=' in clk_scl) and \
not (clk_scl.startswith('(') and clk_scl.endswith(')')):
clk_scl_formatted = f"({clk_scl})"
# 4. Generar Lógica SCL del *pulso*
result_pulse_expression = "FALSE"
scl_comment = ""
if instr_type_original == "PBox": # P_TRIG
result_pulse_expression = f"{clk_scl_formatted} AND NOT {mem_bit_scl_original}"
scl_comment = f"// P_TRIG({clk_scl_formatted})"
elif instr_type_original == "NBox": # N_TRIG
result_pulse_expression = f"NOT {clk_scl_formatted} AND {mem_bit_scl_original}"
scl_comment = f"// N_TRIG({clk_scl_formatted})"
else: # Error
instruction["scl"] = f"// ERROR: Tipo de flanco inesperado {instr_type_original}"
instruction["type"] = instr_type_original + "_error"
return True
# 5. Generar la actualización del bit de memoria
scl_mem_update = f"{mem_bit_scl_original} := {clk_scl_formatted};"
# 6. Almacenar Resultados
map_key_out = (network_id, instr_uid, "out")
scl_map[map_key_out] = result_pulse_expression # Guardar EXPRESIÓN del pulso
instruction['_edge_mem_update_scl'] = scl_mem_update # Guardar UPDATE en campo temporal
instruction['scl'] = f"{scl_comment} (Mem update handled by consumer)" # Dejar SCL principal vacío/comentario
instruction["type"] = instr_type_original + SCL_SUFFIX
# 7. Propagar ENO
map_key_eno = (network_id, instr_uid, "eno")
scl_map[map_key_eno] = clk_scl
return True
# --- process_coil MODIFICADA ---
def process_coil(instruction, network_id, scl_map, access_map):
"""Genera la asignación para Coil. Si la entrada viene de PBox/NBox,
añade la actualización de memoria del flanco DESPUÉS de la asignación."""
instr_uid = instruction["instruction_uid"]
instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
return False
coil_input_info = instruction["inputs"].get("in")
operand_info = instruction["inputs"].get("operand")
in_rlo_scl = get_scl_representation(coil_input_info, network_id, scl_map, access_map)
operand_scl = get_scl_representation(operand_info, network_id, scl_map, access_map)
if in_rlo_scl is None or operand_scl is None: return False
if not (operand_info and operand_info.get("type") == "variable"):
instruction["scl"] = f"// ERROR: Coil {instr_uid} operando no es variable o falta info"
instruction["type"] = instr_type + "_error"
return True
operand_scl_formatted = format_variable_name(operand_scl)
if in_rlo_scl == "(TRUE)": in_rlo_scl = "TRUE"
elif in_rlo_scl == "(FALSE)": in_rlo_scl = "FALSE"
# Generar la asignación SCL principal
scl_assignment = f"{operand_scl_formatted} := {in_rlo_scl};"
scl_final = scl_assignment # Inicializar SCL final
# --- Lógica para añadir actualización de memoria de flancos ---
mem_update_scl = None
if isinstance(coil_input_info, dict) and coil_input_info.get("type") == "connection":
source_uid = coil_input_info.get("source_instruction_uid")
source_pin = coil_input_info.get("source_pin")
# Buscar la instrucción fuente en la lógica de la red actual
source_instruction = None
network_logic = next((net["logic"] for net in data["networks"] if net["id"] == network_id), [])
for instr in network_logic:
if instr.get("instruction_uid") == source_uid:
source_instruction = instr
break
if source_instruction:
source_type = source_instruction.get("type","").replace('_scl','').replace('_error','')
# Si la fuente es PBox o NBox y tiene el campo temporal con la actualización
if source_type in ["PBox", "NBox"] and '_edge_mem_update_scl' in source_instruction:
mem_update_scl = source_instruction['_edge_mem_update_scl']
# Añadir la actualización DESPUÉS de la asignación de la bobina
scl_final = f"{scl_assignment}\\n{mem_update_scl} {source_instruction.get('scl', '')}" # Añadir también comentario original del PBox/NBox
# Marcar la instrucción PBox/NBox para que x3 no escriba su SCL (que ahora está vacío/comentario)
source_instruction['scl'] = f"// Logic moved to Coil {instr_uid}"
instruction["scl"] = scl_final
instruction["type"] = instr_type + SCL_SUFFIX
return True
def process_convert(instruction, network_id, scl_map, access_map):
instr_uid = instruction["instruction_uid"]
instr_type = instruction["type"]
@ -1372,7 +1380,7 @@ def process_json_to_scl(json_filepath):
# --- Ejecución ---
if __name__ == "__main__":
# Asegúrate de que el nombre base del archivo XML sea correcto
xml_filename_base = "BlenderRun_ProdTime" # Cambia esto si tu XML se llama diferente
xml_filename_base = "TestLAD" # Cambia esto si tu XML se llama diferente
input_json_file = f"{xml_filename_base}_simplified.json"
if not os.path.exists(input_json_file):

View File

@ -197,7 +197,7 @@ def generate_scl(processed_json_filepath, output_scl_filepath):
# --- Ejecución ---
if __name__ == "__main__":
xml_file = "BlenderRun_ProdTime.xml" # CAMBIAR AL NUEVO ARCHIVO XML
xml_file = "TestLAD.xml" # CAMBIAR AL NUEVO ARCHIVO XML
input_json_file = xml_file.replace(
".xml", "_simplified_processed.json"
) # Nombre de salida dinámico

508
xcopy.py
View File

@ -1,508 +0,0 @@
# -*- coding: utf-8 -*-
import json
import os
import copy
import traceback
import re
# --- Constantes y Configuración ---
SCL_SUFFIX = "_scl"
GROUPED_COMMENT = "// Logic included in grouped IF"
# Global data variable
data = {}
# --- 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):
# ... (código sin cambios)
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")
return (
format_variable_name(name) # Asegura formato correcto aquí también
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": str_val = str(value).replace("'", "''"); return f"'{str_val}'"
elif dtype == "TYPEDCONSTANT": return str(value) # Ej: T#5s
else: 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):
# ... (código sin cambios)
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
def generate_temp_var_name(network_id, instr_uid, pin_name):
# ... (código sin cambios)
net_id_clean = str(network_id).replace("-", "_")
instr_uid_clean = str(instr_uid).replace("-", "_")
pin_name_clean = str(pin_name).replace("-", "_").lower()
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):
# ... (código sin cambios)
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)
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)
if target_scl is None and not default_to_temp: return None
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
# --- Procesadores de Instrucciones ---
# (process_contact, process_eq, process_coil, process_convert, process_mod,
# process_add, process_move, process_o, process_call - sin cambios significativos)
# ... (resto de procesadores base aquí) ...
def process_contact(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
is_negated = instruction.get("negated_pins", {}).get("operand", False)
in_input = instruction["inputs"].get("in")
in_rlo_scl = "TRUE" if in_input is None else get_scl_representation(in_input, 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: return False
term = f"NOT {operand_scl}" if is_negated else operand_scl
if not (term.startswith('"') and term.endswith('"')):
if is_negated or (" " in term and not (term.startswith("(") and term.endswith(")"))): term = f"({term})"
new_rlo_scl = term if in_rlo_scl == "TRUE" else (f"({in_rlo_scl}) AND {term}" if ("AND" in in_rlo_scl or "OR" in in_rlo_scl) and not (in_rlo_scl.startswith("(") and in_rlo_scl.endswith(")")) else f"{in_rlo_scl} AND {term}")
map_key = (network_id, instr_uid, "out"); scl_map[map_key] = new_rlo_scl
instruction["scl"] = f"// RLO: {new_rlo_scl}"; instruction["type"] = instr_type + SCL_SUFFIX
return True
def process_eq(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
in1_info = instruction["inputs"].get("in1"); in2_info = instruction["inputs"].get("in2")
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map); in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
if in1_scl is None or in2_scl is None: return False
op1 = format_variable_name(in1_scl) if in1_info and in1_info.get("type") == "variable" else in1_scl
op2 = format_variable_name(in2_scl) if in2_info and in2_info.get("type") == "variable" else in2_scl
op1 = f"({op1})" if " " in op1 and not op1.startswith("(") else op1; op2 = f"({op2})" if " " in op2 and not op2.startswith("(") else op2
comparison_scl = f"{op1} = {op2}"; map_key_out = (network_id, instr_uid, "out"); scl_map[map_key_out] = comparison_scl
pre_input = instruction["inputs"].get("pre"); pre_scl = "TRUE" if pre_input is None else get_scl_representation(pre_input, network_id, scl_map, access_map)
if pre_scl is None: return False
map_key_eno = (network_id, instr_uid, "eno"); scl_map[map_key_eno] = pre_scl
instruction["scl"] = f"// Comparison Eq {instr_uid}: {comparison_scl}"; instruction["type"] = instr_type + SCL_SUFFIX
return True
def process_coil(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
in_rlo_scl = get_scl_representation(instruction["inputs"].get("in"), network_id, scl_map, access_map)
operand_info = instruction["inputs"].get("operand"); operand_scl = get_scl_representation(operand_info, network_id, scl_map, access_map)
if in_rlo_scl is None or operand_scl is None: return False
if not (operand_info and operand_info.get("type") == "variable"): print(f"Error: Operando COIL {instr_uid} no es variable o falta información."); instruction["scl"] = f"// ERROR: Coil {instr_uid} operando no es variable o falta info"; instruction["type"] = instr_type + "_error"; return True
operand_scl_formatted = format_variable_name(operand_scl)
if in_rlo_scl == "(TRUE)": in_rlo_scl = "TRUE";
elif in_rlo_scl == "(FALSE)": in_rlo_scl = "FALSE"
scl_final = f"{operand_scl_formatted} := {in_rlo_scl};"; instruction["scl"] = scl_final; instruction["type"] = instr_type + SCL_SUFFIX
return True
def process_convert(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"];
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
en_input = instruction["inputs"].get("en"); en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) if en_input else "TRUE"
in_info = instruction["inputs"].get("in"); in_scl = get_scl_representation(in_info, network_id, scl_map, access_map)
if en_scl is None or in_scl is None: return False
target_scl = get_target_scl_name(instruction, "out", network_id, default_to_temp=True)
if target_scl is None: print(f"Error: Sin destino claro para CONVERT {instr_uid}"); instruction["scl"] = f"// ERROR: Convert {instr_uid} sin destino"; instruction["type"] += "_error"; return True
in_scl_formatted = format_variable_name(in_scl) if in_info and in_info.get("type") == "variable" else in_scl
conversion_expr = in_scl_formatted # Simplificación, asume asignación directa
scl_core = f"{target_scl} := {conversion_expr};"
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
instruction["scl"] = scl_final; instruction["type"] = instr_type + SCL_SUFFIX
map_key_out = (network_id, instr_uid, "out"); scl_map[map_key_out] = target_scl
map_key_eno = (network_id, instr_uid, "eno"); scl_map[map_key_eno] = en_scl
return True
def process_mod(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"];
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
en_input = instruction["inputs"].get("en"); en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) if en_input else "TRUE"
in1_info = instruction["inputs"].get("in1"); in2_info = instruction["inputs"].get("in2")
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map); in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
if en_scl is None or in1_scl is None or in2_scl is None: return False
target_scl = get_target_scl_name(instruction, "out", network_id, default_to_temp=True)
if target_scl is None: print(f"Error: Sin destino MOD {instr_uid}"); instruction["scl"] = f"// ERROR: Mod {instr_uid} sin destino"; instruction["type"] += "_error"; return True
op1 = format_variable_name(in1_scl) if in1_info and in1_info.get("type") == "variable" else in1_scl
op2 = format_variable_name(in2_scl) if in2_info and in2_info.get("type") == "variable" else in2_scl
op1 = f"({op1})" if " " in op1 and not op1.startswith("(") else op1; op2 = f"({op2})" if " " in op2 and not op2.startswith("(") else op2
scl_core = f"{target_scl} := {op1} MOD {op2};"; scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
instruction["scl"] = scl_final; instruction["type"] = instr_type + SCL_SUFFIX
map_key_out = (network_id, instr_uid, "out"); scl_map[map_key_out] = target_scl
map_key_eno = (network_id, instr_uid, "eno"); scl_map[map_key_eno] = en_scl
return True
def process_add(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
en_input = instruction["inputs"].get("en"); en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) if en_input else "TRUE"
in1_info = instruction["inputs"].get("in1"); in2_info = instruction["inputs"].get("in2")
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map); in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
if en_scl is None or in1_scl is None or in2_scl is None: return False
target_scl = get_target_scl_name(instruction, "out", network_id, default_to_temp=True)
if target_scl is None: print(f"Error: Sin destino ADD {instr_uid}"); instruction["scl"] = f"// ERROR: Add {instr_uid} sin destino"; instruction["type"] += "_error"; return True
op1 = format_variable_name(in1_scl) if in1_info and in1_info.get("type") == "variable" else in1_scl
op2 = format_variable_name(in2_scl) if in2_info and in2_info.get("type") == "variable" else in2_scl
op1 = f"({op1})" if " " in op1 and not op1.startswith("(") else op1; op2 = f"({op2})" if " " in op2 and not op2.startswith("(") else op2
scl_core = f"{target_scl} := {op1} + {op2};"; scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
instruction["scl"] = scl_final; instruction["type"] = instr_type + SCL_SUFFIX
map_key_out = (network_id, instr_uid, "out"); scl_map[map_key_out] = target_scl
map_key_eno = (network_id, instr_uid, "eno"); scl_map[map_key_eno] = en_scl
return True
def process_move(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
en_input = instruction["inputs"].get("en"); en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) if en_input else "TRUE"
in_info = instruction["inputs"].get("in"); in_scl = get_scl_representation(in_info, network_id, scl_map, access_map)
if en_scl is None or in_scl is None: return False
target_scl = get_target_scl_name(instruction, "out1", network_id, default_to_temp=False)
if target_scl is None: target_scl = get_target_scl_name(instruction, "out", network_id, default_to_temp=False)
if target_scl is None: print(f"Advertencia/Error: MOVE {instr_uid} sin destino claro en 'out' o 'out1'."); return False
in_scl_formatted = format_variable_name(in_scl) if in_info and in_info.get("type") == "variable" else in_scl
scl_core = f"{target_scl} := {in_scl_formatted};"; scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
instruction["scl"] = scl_final; instruction["type"] = instr_type + SCL_SUFFIX
map_key_out = (network_id, instr_uid, "out"); scl_map[map_key_out] = target_scl
map_key_out1 = (network_id, instr_uid, "out1"); scl_map[map_key_out1] = target_scl
map_key_eno = (network_id, instr_uid, "eno"); scl_map[map_key_eno] = en_scl
return True
# --- NUEVA FUNCIÓN UNIFICADA para PBox y NBox ---
def process_edge_detector(instruction, network_id, scl_map, access_map):
"""Genera SCL para PBox (P_TRIG) o NBox (N_TRIG)."""
instr_uid = instruction["instruction_uid"]
instr_type_original = instruction["type"] # PBox o NBox
if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
return False
# Obtener CLK (señal de entrada) y MemBit (bit de memoria)
clk_input = instruction["inputs"].get("in")
mem_bit_input = instruction["inputs"].get("bit")
clk_scl = get_scl_representation(clk_input, network_id, scl_map, access_map)
mem_bit_scl_original = get_scl_representation(mem_bit_input, network_id, scl_map, access_map)
if clk_scl is None or mem_bit_scl_original is None:
# print(f"DEBUG Edge: Esperando dependencias para {instr_type_original} UID {instr_uid}")
return False # Dependencias no listas
# Validar que el bit de memoria sea una variable
if not (mem_bit_input and mem_bit_input.get("type") == "variable"):
print(f"Error: {instr_type_original} {instr_uid} 'bit' no es variable o falta información.")
instruction["scl"] = f"// ERROR: {instr_type_original} {instr_uid} 'bit' no es variable."
instruction["type"] = instr_type_original + "_error"
return True # Procesado con error
# --- Renombrar bit de memoria para VAR_STAT ---
# Quitar comillas existentes, añadir prefijo "stat_" y volver a añadir comillas
mem_bit_name_clean = mem_bit_scl_original.strip('"')
stat_mem_bit_scl = f'"stat_{mem_bit_name_clean}"' # Nombre SCL para la variable estática
# Asegurar paréntesis alrededor de CLK si es complejo
clk_scl_formatted = clk_scl
if (' ' in clk_scl or 'AND' in clk_scl or 'OR' in clk_scl) and not (clk_scl.startswith('(') and clk_scl.endswith(')')):
clk_scl_formatted = f"({clk_scl})"
# --- Generar Lógica SCL ---
result_scl = "FALSE" # SCL para la salida del flanco (pin 'out')
scl_comment = "" # Comentario informativo
if instr_type_original == "PBox": # Flanco Positivo (P_TRIG)
result_scl = f"{clk_scl_formatted} AND NOT {stat_mem_bit_scl}"
scl_comment = f"// P_TRIG: {result_scl}"
elif instr_type_original == "NBox": # Flanco Negativo (N_TRIG)
result_scl = f"NOT {clk_scl_formatted} AND {stat_mem_bit_scl}"
scl_comment = f"// N_TRIG: {result_scl}"
else:
# No debería ocurrir si el mapeo de procesadores es correcto
print(f"Error interno: process_edge_detector llamado para tipo inesperado {instr_type_original}")
instruction["scl"] = f"// ERROR: Tipo de flanco inesperado {instr_type_original}"
instruction["type"] = instr_type_original + "_error"
return True
# La actualización del bit de memoria es igual para P_TRIG y N_TRIG estándar
scl_mem_update = f"{stat_mem_bit_scl} := {clk_scl_formatted};"
# --- Almacenar Resultados ---
# El pulso resultante va al mapa SCL para que lo usen las instrucciones siguientes
map_key_out = (network_id, instr_uid, "out")
scl_map[map_key_out] = result_scl
# La actualización de memoria es la acción principal de esta instrucción en SCL
instruction["scl"] = f"{scl_mem_update} {scl_comment}"
instruction["type"] = instr_type_original + SCL_SUFFIX
# El pin ENO normalmente sigue al CLK en los bloques de flanco estándar
map_key_eno = (network_id, instr_uid, "eno")
scl_map[map_key_eno] = clk_scl # Usar clk_scl original sin formateo extra
return True
# --- FIN NUEVA FUNCIÓN UNIFICADA ---
def process_o(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"]
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
input_pins = sorted([pin for pin in instruction["inputs"] if pin.startswith("in")])
if not input_pins: print(f"Error: O {instr_uid} sin pines de entrada (inX)."); instruction["scl"] = f"// ERROR: O {instr_uid} sin pines inX"; instruction["type"] += "_error"; return True
scl_parts = []; all_resolved = True
for pin in input_pins:
in_scl = get_scl_representation(instruction["inputs"][pin], network_id, scl_map, access_map)
if in_scl is None: all_resolved = False; break
term = in_scl;
if (" " in term or "AND" in term) and not (term.startswith("(") and term.endswith(")")): term = f"({term})"
scl_parts.append(term)
if not all_resolved: return False
result_scl = "FALSE";
if scl_parts:
result_scl = " OR ".join(scl_parts)
if len(scl_parts) == 1: result_scl = scl_parts[0]
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_call(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction.get("type", "")
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")
instance_db = instruction.get("instance_db"); instance_db_scl = format_variable_name(instance_db) if instance_db else None
block_name_scl = format_variable_name(block_name)
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
scl_call_params = []; processed_inputs = {"en"}
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: return False
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)
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
scl_call_body = f"{instance_db_scl}({param_string});"
elif block_type == "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"
scl_final = "";
if en_scl != "TRUE": 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
instruction["scl"] = scl_final; instruction["type"] = f"Call_{block_type}_scl" if "_error" not in instruction["type"] else instruction["type"]
map_key_eno = (network_id, instr_uid, "eno"); scl_map[map_key_eno] = en_scl
return True
# --- Procesador de Agrupación (Sin cambios) ---
def process_group_ifs(instruction, network_id, scl_map, access_map):
# ... (código sin cambios) ...
instr_uid = instruction["instruction_uid"]; instr_type = instruction["type"]; instr_type_original = instr_type.replace("_scl", "").replace("_error", "")
made_change = False
if (not instr_type.endswith("_scl") or "_error" in instr_type or instruction.get("grouped", False) or instr_type_original not in ["Contact", "O", "Eq", "Ne", "Gt", "Lt", "Ge", "Le", "PBox", "NBox", "And", "Xor"]): return False # Añadido NBox aquí
current_scl = instruction.get("scl", "")
if (current_scl.strip().startswith("IF") and "END_IF;" in current_scl) or (current_scl.strip().startswith("//") and "IF" in current_scl): return False
map_key_out = (network_id, instr_uid, "out"); condition_scl = scl_map.get(map_key_out)
if condition_scl is None or condition_scl in ["TRUE", "FALSE"]: return False
grouped_instructions_cores = []; consumer_instr_list = []
network_logic = next((net["logic"] for net in data["networks"] if net["id"] == network_id), []);
if not network_logic: return False
groupable_types = ["Move", "Add", "Sub", "Mul", "Div", "Mod", "Convert", "Call_FC", "Call_FB"]
for consumer_instr in network_logic:
consumer_uid = consumer_instr["instruction_uid"]
if consumer_instr.get("grouped", False) or consumer_uid == instr_uid: continue
consumer_en = consumer_instr.get("inputs", {}).get("en"); consumer_type = consumer_instr.get("type", ""); consumer_type_original = consumer_type.replace("_scl", "").replace("_error", "")
is_enabled_by_us = False
if (isinstance(consumer_en, dict) and consumer_en.get("type") == "connection" and consumer_en.get("source_instruction_uid") == instr_uid and consumer_en.get("source_pin") == "out"): is_enabled_by_us = True
if (is_enabled_by_us and consumer_type.endswith("_scl") and consumer_type_original in groupable_types):
consumer_scl = consumer_instr.get("scl", ""); core_scl = None
if consumer_scl.strip().startswith("IF"):
match = re.search(r"IF\\s+.*\\s+THEN\\s*(.*?)\\s*END_IF;", consumer_scl, re.DOTALL | re.IGNORECASE)
if match: core_scl = match.group(1).strip()
elif consumer_scl and not consumer_scl.strip().startswith("//"): core_scl = consumer_scl.strip()
if core_scl: grouped_instructions_cores.append(core_scl); consumer_instr_list.append(consumer_instr)
if len(grouped_instructions_cores) > 1:
print(f"INFO: Agrupando {len(grouped_instructions_cores)} instrucciones bajo condición de {instr_type_original} UID {instr_uid} (Cond: {condition_scl})")
scl_grouped = [f"IF {condition_scl} THEN"]
for core_line in grouped_instructions_cores: indented_core = "\\n".join([f" {line.strip()}" for line in core_line.splitlines()]); scl_grouped.append(indented_core)
scl_grouped.append("END_IF;"); final_grouped_scl = "\\n".join(scl_grouped)
instruction["scl"] = final_grouped_scl
for consumer_instr in consumer_instr_list: consumer_instr["scl"] = f"{GROUPED_COMMENT} (by UID {instr_uid})"; consumer_instr["grouped"] = True
made_change = True
return made_change
# --- Bucle Principal de Procesamiento ---
def process_json_to_scl(json_filepath):
# ... (Inicio sin cambios) ...
if not os.path.exists(json_filepath): print(f"Error: JSON no encontrado: {json_filepath}"); return
print(f"Cargando JSON desde: {json_filepath}")
try: global data; data = json.load(f)
except Exception as e: print(f"Error al cargar JSON: {e}"); traceback.print_exc(); return
network_access_maps = {}
for network in data.get("networks", []):
net_id = network["id"]; current_access_map = {}
for instr in network.get("logic", []):
for _, 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("type") in ["variable", "constant"]: current_access_map[src["uid"]] = src
for _, 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("type") in ["variable", "constant"]: current_access_map[dest["uid"]] = dest
network_access_maps[net_id] = current_access_map
scl_map = {}
max_passes = 30; passes = 0; processing_complete = False
# --- MODIFICACIÓN: Añadir process_edge_detector al mapa ---
base_processors = [
process_convert, process_mod, process_eq, process_contact, process_o,
process_edge_detector, # Usar la nueva función unificada
process_add, process_move, process_call, process_coil,
# ... otros procesadores base ...
]
processor_map = {}
for func in base_processors:
match = re.match(r"process_(\w+)", func.__name__)
if match:
type_name = match.group(1).lower()
if type_name == "call":
processor_map["call_fc"] = func; processor_map["call_fb"] = func; processor_map["call"] = func
elif type_name == "edge_detector": # Mapear PBox y NBox a la nueva función
processor_map["pbox"] = func
processor_map["nbox"] = func
else: processor_map[type_name] = func
# --- FIN MODIFICACIÓN ---
print("\\n--- Iniciando Bucle de Procesamiento Iterativo ---")
while passes < max_passes and not processing_complete:
# ... (Lógica del bucle iterativo sin cambios,
# ahora usará process_edge_detector para PBox y NBox
# a través del processor_map actualizado) ...
passes += 1; made_change_in_base_pass = False; made_change_in_group_pass = False
print(f"\\n--- Pase {passes} ---"); num_processed_this_pass = 0; num_grouped_this_pass = 0
for network in data.get("networks", []):
network_id = network["id"]; access_map = network_access_maps.get(network_id, {})
network_logic = network.get("logic", [])
for instruction in network_logic:
instr_uid = instruction.get("instruction_uid"); instr_type_original = instruction.get("type", "Unknown")
if (instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original or instruction.get("grouped", False)): continue
lookup_key = instr_type_original.lower()
if instr_type_original == "Call":
block_type = instruction.get("block_type", "").upper()
if block_type == "FC": lookup_key = "call_fc"
elif block_type == "FB": lookup_key = "call_fb"
func_to_call = processor_map.get(lookup_key)
if func_to_call:
try:
# No necesita pasar network_logic excepto para la versión anterior de PBox
changed = func_to_call(instruction, network_id, scl_map, access_map)
if changed: made_change_in_base_pass = True; num_processed_this_pass += 1
except Exception as e: print(f"ERROR(Base) al procesar {instr_type_original} UID {instr_uid} con {func_to_call.__name__}: {e}"); traceback.print_exc(); instruction["scl"] = f"// ERROR en procesador base: {e}"; instruction["type"] = instr_type_original + "_error"; made_change_in_base_pass = True
if made_change_in_base_pass or passes == 1:
for network in data.get("networks", []):
network_id = network["id"]; access_map = network_access_maps.get(network_id, {}); network_logic = network.get("logic", [])
for instruction in network_logic:
if instruction["type"].endswith("_scl") and not instruction.get("grouped", False):
try:
group_changed = process_group_ifs(instruction, network_id, scl_map, access_map)
if group_changed: made_change_in_group_pass = True; num_grouped_this_pass += 1
except Exception as e: print(f"ERROR(Group) al intentar agrupar desde UID {instruction.get('instruction_uid')}: {e}"); traceback.print_exc()
if not made_change_in_base_pass and not made_change_in_group_pass: print(f"\\n--- No se hicieron más cambios en el pase {passes}. Proceso iterativo completado. ---"); processing_complete = True
else: print(f"--- Fin Pase {passes}: {num_processed_this_pass} procesados, {num_grouped_this_pass} agrupados. Continuando...")
if passes == max_passes and not processing_complete: print(f"\\n--- ADVERTENCIA: Límite de {max_passes} pases alcanzado. Puede haber dependencias no resueltas. ---")
# --- Verificación Final y Guardado (Sin cambios) ---
print("\\n--- Verificación Final de Instrucciones No Procesadas ---"); unprocessed_count = 0; unprocessed_details = []
for network in data.get("networks", []):
network_id = network.get("id", "Unknown ID"); network_title = network.get("title", f"Network {network_id}")
for instruction in network.get("logic", []):
instr_uid = instruction.get("instruction_uid", "Unknown UID"); instr_type = instruction.get("type", "Unknown Type"); is_grouped = instruction.get("grouped", False)
if (not instr_type.endswith(SCL_SUFFIX) and "_error" not in instr_type and not is_grouped):
unprocessed_count += 1; unprocessed_details.append(f" - Red '{network_title}' (ID: {network_id}), Instrucción UID: {instr_uid}, Tipo Original: '{instr_type}'")
if unprocessed_count > 0: print(f"ADVERTENCIA: Se encontraron {unprocessed_count} instrucciones que no pudieron ser procesadas a SCL:");
for detail in unprocessed_details: print(detail)
print(">>> Estos tipos de instrucción podrían necesitar un procesador específico en 'x2_process.py'.")
else: print("INFO: Todas las instrucciones fueron procesadas a SCL, marcadas como error o agrupadas exitosamente.")
output_filename = json_filepath.replace("_simplified.json", "_simplified_processed.json")
print(f"\\nGuardando JSON procesado en: {output_filename}")
try:
with open(output_filename, "w", encoding="utf-8") as f: json.dump(data, f, indent=4, ensure_ascii=False)
print("Guardado completado.")
except Exception as e: print(f"Error Crítico al guardar JSON procesado: {e}"); traceback.print_exc()
# --- Ejecución ---
if __name__ == "__main__":
# Asegurarse de usar el nombre base del XML de prueba
xml_filename_base = "TestLAD" # <--- CAMBIADO PARA USAR TestLAD
input_json_file = f"{xml_filename_base}_simplified.json"
if not os.path.exists(input_json_file): print(f"Error Fatal: El archivo de entrada JSON simplificado no existe: '{input_json_file}'"); print("Asegúrate de haber ejecutado 'x1_to_json.py' primero sobre el archivo XML correcto.")
else: process_json_to_scl(input_json_file)