diff --git a/BlenderRun_ProdTime_simplified.json b/BlenderRun_ProdTime_simplified.json index 16c2a83..4863c15 100644 --- a/BlenderRun_ProdTime_simplified.json +++ b/BlenderRun_ProdTime_simplified.json @@ -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": { diff --git a/BlenderRun_ProdTime_simplified_processed.json b/BlenderRun_ProdTime_simplified_processed.json index 3bc8396..93ab33c 100644 --- a/BlenderRun_ProdTime_simplified_processed.json +++ b/BlenderRun_ProdTime_simplified_processed.json @@ -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": { diff --git a/BlenderRun_ProdTime_simplified_processed.scl b/BlenderRun_ProdTime_simplified_processed.scl.txt similarity index 95% rename from BlenderRun_ProdTime_simplified_processed.scl rename to BlenderRun_ProdTime_simplified_processed.scl.txt index c941ca2..b8cd676 100644 --- a/BlenderRun_ProdTime_simplified_processed.scl +++ b/BlenderRun_ProdTime_simplified_processed.scl.txt @@ -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 diff --git a/TestLAD.xml b/TestLAD.xml index 9f2f212..1b377cb 100644 --- a/TestLAD.xml +++ b/TestLAD.xml @@ -7,7 +7,15 @@
-
+
+ + + + + + + +
@@ -69,54 +77,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + LAD @@ -171,7 +132,7 @@ it-IT - Clock Bit + @@ -220,47 +181,55 @@ - + - + + - + - + - - - + + + + + + + + + Variant + - + - + - - + + - + - - + + - - + + @@ -318,7 +287,7 @@ it-IT - Clock Bit + Filler Head @@ -361,145 +330,45 @@ - - - - LAD - + - - - - - it-IT - - - - - - de-DE - - - - - - en-US - - - - - - es-ES - - - - - - fr-FR - - - - - - zh-CN - - - - - - ja-JP - - - - - - - - - - it-IT - - - - - - de-DE - - - - - - en-US - - - - - - es-ES - - - - - - fr-FR - - - - - - zh-CN - - - - - - ja-JP - - - - - - - - - - + it-IT - + de-DE - + en-US - + es-ES - + fr-FR - + zh-CN - + ja-JP diff --git a/TestLAD_simplified.json b/TestLAD_simplified.json index 75a7fd6..b4c364d 100644 --- a/TestLAD_simplified.json +++ b/TestLAD_simplified.json @@ -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\"" + } + ] + } } ] } diff --git a/TestLAD_simplified_processed.json b/TestLAD_simplified_processed.json index 9d77568..cb55b91 100644 --- a/TestLAD_simplified_processed.json +++ b/TestLAD_simplified_processed.json @@ -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\"" + } + ] + } } ] } diff --git a/TestLAD_simplified_processed.scl b/TestLAD_simplified_processed.scl index 35afe86..a7e9b16 100644 --- a/TestLAD_simplified_processed.scl +++ b/TestLAD_simplified_processed.scl @@ -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 diff --git a/x1_to_json.py b/x1_to_json.py index 76bbf58..3f84c79 100644 --- a/x1_to_json.py +++ b/x1_to_json.py @@ -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) \ No newline at end of file diff --git a/x2_process.py b/x2_process.py index 2c4fa62..fb8bd98 100644 --- a/x2_process.py +++ b/x2_process.py @@ -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): diff --git a/x3_generate_scl.py b/x3_generate_scl.py index 833215e..726ebdf 100644 --- a/x3_generate_scl.py +++ b/x3_generate_scl.py @@ -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 diff --git a/xcopy.py b/xcopy.py deleted file mode 100644 index 72e8a25..0000000 --- a/xcopy.py +++ /dev/null @@ -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) \ No newline at end of file