Compare commits
5 Commits
75cd67c446
...
607e3105b5
Author | SHA1 | Date |
---|---|---|
|
607e3105b5 | |
|
45c34c7dca | |
|
d6125f9433 | |
|
4bf7619cc1 | |
|
b2d3f0f5bf |
|
@ -1,93 +0,0 @@
|
|||
{
|
||||
"block_name": "BlenderCtrl_ProdModeInit",
|
||||
"block_number": 2012,
|
||||
"language": "LAD",
|
||||
"block_comment": "",
|
||||
"interface": {
|
||||
"Return": [
|
||||
{
|
||||
"name": "Ret_Val",
|
||||
"datatype": "Void"
|
||||
}
|
||||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "PID Reset Integral",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call",
|
||||
"block_name": "BlenderPID_PIDResInteg",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Ctrl Init Errors",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call",
|
||||
"block_name": "BlenderCtrl_InitErrors",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "RunOut Counter",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Move",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Real",
|
||||
"value": 0.0
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
"out1": [
|
||||
{
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"HMI_Variables_Status\".\"Analog_Values\".\"TP301RunOutCount\""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
{
|
||||
"block_name": "BlenderCtrl_ProdModeInit",
|
||||
"block_number": 2012,
|
||||
"language": "LAD",
|
||||
"block_comment": "",
|
||||
"interface": {
|
||||
"Return": [
|
||||
{
|
||||
"name": "Ret_Val",
|
||||
"datatype": "Void"
|
||||
}
|
||||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "PID Reset Integral",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call_FC_scl",
|
||||
"block_name": "BlenderPID_PIDResInteg",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "BlenderPID_PIDResInteg();"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Ctrl Init Errors",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "21",
|
||||
"uid": "21",
|
||||
"type": "Call_FC_scl",
|
||||
"block_name": "BlenderCtrl_InitErrors",
|
||||
"block_type": "FC",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "BlenderCtrl_InitErrors();"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "RunOut Counter",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Move_scl",
|
||||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "LiteralConstant",
|
||||
"type": "constant",
|
||||
"datatype": "Real",
|
||||
"value": 0.0
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
"out1": [
|
||||
{
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"HMI_Variables_Status\".\"Analog_Values\".\"TP301RunOutCount\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"scl": "\"HMI_Variables_Status\".\"Analog_Values\".\"TP301RunOutCount\" := 0.0;"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
// Block Name (Original): BlenderCtrl_ProdModeInit
|
||||
// Block Number: 2012
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "BlenderCtrl_ProdModeInit"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: PID Reset Integral
|
||||
|
||||
BlenderPID_PIDResInteg();
|
||||
|
||||
// Network 2: Ctrl Init Errors
|
||||
|
||||
BlenderCtrl_InitErrors();
|
||||
|
||||
// Network 3: RunOut Counter
|
||||
|
||||
"HMI_Variables_Status"."Analog_Values"."TP301RunOutCount" := 0.0;
|
||||
|
||||
END_FUNCTION_BLOCK
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -29,7 +29,7 @@ BEGIN
|
|||
|
||||
// Network 1: Clock Generation
|
||||
|
||||
Clock Signal();
|
||||
Clock_Signal();
|
||||
|
||||
// Network 2: Machine Init
|
||||
|
||||
|
@ -47,12 +47,12 @@ BEGIN
|
|||
|
||||
// RLO: "gIN_LinePressCO2Ok"
|
||||
// RLO: "gWorkshopTest"
|
||||
// RLO: "gWorkshopTest" AND "gWorkshop_Co2_Presence"
|
||||
// RLO: ("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals"
|
||||
// RLO: ("gIN_LinePressCO2Ok" OR (("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered"
|
||||
// RLO: "Disable_Bit"
|
||||
// RLO: ((("gIN_LinePressCO2Ok" OR (("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered") OR "Disable_Bit") AND "gIN_VoltageOk"
|
||||
"gBlenderSuppliesOk" := ((("gIN_LinePressCO2Ok" OR (("gWorkshopTest" AND "gWorkshop_Co2_Presence") AND "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered") OR "Disable_Bit") AND "gIN_VoltageOk";
|
||||
// RLO: "gWorkshopTest" AND (NOT "gWorkshop_Co2_Presence")
|
||||
// RLO: ("gWorkshopTest" AND (NOT "gWorkshop_Co2_Presence")) AND (NOT "gWorkshop_CIP_Signals")
|
||||
// RLO: ("gIN_LinePressCO2Ok" OR ("gWorkshopTest" AND (NOT "gWorkshop_Co2_Presence")) AND (NOT "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered"
|
||||
// RLO: (NOT "Disable_Bit")
|
||||
// RLO: (("gIN_LinePressCO2Ok" OR ("gWorkshopTest" AND (NOT "gWorkshop_Co2_Presence")) AND (NOT "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered") OR (NOT "Disable_Bit") AND "gIN_VoltageOk"
|
||||
"gBlenderSuppliesOk" := (("gIN_LinePressCO2Ok" OR ("gWorkshopTest" AND (NOT "gWorkshop_Co2_Presence")) AND (NOT "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered") OR (NOT "Disable_Bit") AND "gIN_VoltageOk";
|
||||
|
||||
// Network 6: Blender State Num
|
||||
|
||||
|
@ -69,49 +69,47 @@ BEGIN
|
|||
|
||||
// Network 9: CIp Mode
|
||||
|
||||
// RLO: "HMI_Variables_Status"."System"."Blender_Prod_CIP"
|
||||
"gBlenderCIPMode" := "HMI_Variables_Status"."System"."Blender_Prod_CIP";
|
||||
IF "HMI_Variables_Status"."System"."Blender_Prod_CIP" THEN
|
||||
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 19;
|
||||
END_IF;
|
||||
// RLO: (NOT "HMI_Variables_Status"."System"."Blender_Prod_CIP")
|
||||
"gBlenderCIPMode" := (NOT "HMI_Variables_Status"."System"."Blender_Prod_CIP");
|
||||
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 19;
|
||||
|
||||
// Network 10: Error Faults
|
||||
|
||||
// RLO: "AUX FALSE"
|
||||
// RLO: (NOT "AUX FALSE")
|
||||
|
||||
// Network 11: Filler Bottle Count Used to push Product
|
||||
|
||||
// RLO: "System_RunOut_Variables"."ProdPipeRunOutWaterCount"
|
||||
"System_RunOut_Variables"."ProdPipeRunOutFillerBott" := "System_RunOut_Variables"."ProdPipeRunOutWaterCount";
|
||||
// RLO: (NOT "System_RunOut_Variables"."ProdPipeRunOutWaterCount")
|
||||
"System_RunOut_Variables"."ProdPipeRunOutFillerBott" := (NOT "System_RunOut_Variables"."ProdPipeRunOutWaterCount");
|
||||
|
||||
// Network 12: Water Bypass Enable
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass"
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair"
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation"
|
||||
// RLO: ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation")) AND "Blender_Variables_Pers"."gWaterRecipe"
|
||||
// RLO: (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation")) AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe"
|
||||
"gStillWaterByPassEn" := (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation")) AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe";
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation")
|
||||
// RLO: ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation"))) AND "Blender_Variables_Pers"."gWaterRecipe"
|
||||
// RLO: (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation"))) AND "Blender_Variables_Pers"."gWaterRecipe") AND (NOT "Blender_Variables_Pers"."gCarboStillRecipe")
|
||||
"gStillWaterByPassEn" := (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_ByPassDeair" AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Deaireation"))) AND "Blender_Variables_Pers"."gWaterRecipe") AND (NOT "Blender_Variables_Pers"."gCarboStillRecipe");
|
||||
|
||||
// Network 13: Still Water Bypass
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem"
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass"
|
||||
// RLO: ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe"
|
||||
// RLO: (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe"
|
||||
"gBlendFiStillWaterByPass" := (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe") AND "Blender_Variables_Pers"."gCarboStillRecipe";
|
||||
// RLO: (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe") AND (NOT "Blender_Variables_Pers"."gCarboStillRecipe")
|
||||
"gBlendFiStillWaterByPass" := (("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_StillWaterByPass") AND "Blender_Variables_Pers"."gWaterRecipe") AND (NOT "Blender_Variables_Pers"."gCarboStillRecipe");
|
||||
|
||||
// Network 14: Manual Syrup Drain Valve Open - Operator Alarm
|
||||
|
||||
// RLO: "gSyrupRoomEn"
|
||||
// RLO: "gSyrupRoomEn" AND "gIN_HVP301_Aux"
|
||||
// RLO: ("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled"
|
||||
// RLO: (("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done"
|
||||
// RLO: ((("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done") AND "Procedure_Variables"."Syr_RunOut"."Done"
|
||||
// RLO: "gSyrupRoomEn" AND (NOT "gIN_HVP301_Aux")
|
||||
// RLO: ("gSyrupRoomEn" AND (NOT "gIN_HVP301_Aux")) AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled")
|
||||
// RLO: ("gSyrupRoomEn" AND (NOT "gIN_HVP301_Aux")) AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done"
|
||||
// RLO: (("gSyrupRoomEn" AND (NOT "gIN_HVP301_Aux")) AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done") AND (NOT "Procedure_Variables"."Syr_RunOut"."Done")
|
||||
// RLO: "gBlenderCIPMode"
|
||||
// RLO: "gBlenderCIPMode" AND "gIN_CIP_CIPRunning"
|
||||
// RLO: ("gBlenderCIPMode" AND "gIN_CIP_CIPRunning") AND "Procedure_Variables"."Blender_Run"."Running"
|
||||
"gHVP301_Open" := (((("gSyrupRoomEn" AND "gIN_HVP301_Aux") AND "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done") AND "Procedure_Variables"."Syr_RunOut"."Done") OR (("gBlenderCIPMode" AND "gIN_CIP_CIPRunning") AND "Procedure_Variables"."Blender_Run"."Running");
|
||||
"gHVP301_Open" := (("gSyrupRoomEn" AND (NOT "gIN_HVP301_Aux")) AND (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_FastChangeOverEnabled") AND "Procedure_Variables"."FTP302Line_Preparation"."Done") AND (NOT "Procedure_Variables"."Syr_RunOut"."Done") OR (("gBlenderCIPMode" AND "gIN_CIP_CIPRunning") AND "Procedure_Variables"."Blender_Run"."Running");
|
||||
|
||||
// Network 15: Manual Syrup Drain Valve Open - Operator Alarm
|
||||
|
||||
|
@ -120,7 +118,6 @@ BEGIN
|
|||
// Network 16: Maselli Control
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
// Cond: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 6
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 6 THEN
|
||||
Maselli_PA_Control();
|
||||
END_IF;
|
||||
|
@ -128,7 +125,6 @@ BEGIN
|
|||
// Network 17: mPDS Control
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
// Cond: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 5
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 5 THEN
|
||||
mPDS_PA_Control();
|
||||
END_IF;
|
||||
|
@ -146,7 +142,6 @@ BEGIN
|
|||
// NOP 0
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
// Cond: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 3
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 3 THEN
|
||||
GetProdBrixCO2_Anal_Inpt();
|
||||
END_IF;
|
||||
|
@ -157,7 +152,7 @@ BEGIN
|
|||
|
||||
// Network 21: Input Data
|
||||
|
||||
// ERROR: Call a bloque no soportado: Input
|
||||
"Input_Data"();
|
||||
|
||||
// Network 22: Sel Brix Source Check
|
||||
|
||||
|
@ -177,32 +172,32 @@ BEGIN
|
|||
// Network 25: Production ONS
|
||||
|
||||
// RLO: "gBlenderProdMode"
|
||||
// PBox 26 - Passing bit: "M19001"
|
||||
// RLO: "M19001" AND "mDelayPowerOnTmr"
|
||||
"gProductionONS" := "M19001" AND "mDelayPowerOnTmr";
|
||||
// // PBox 26 - Passing memory bit: "M19001"
|
||||
// RLO: "M19001" AND (NOT "mDelayPowerOnTmr")
|
||||
"gProductionONS" := "M19001" AND (NOT "mDelayPowerOnTmr");
|
||||
|
||||
// Network 26: Blender Prod Mode Init
|
||||
|
||||
// RLO: "gProductionONS"
|
||||
// RLO: "Procedure_Variables"."Blender_Rinse"."ONS_Done"
|
||||
// RLO: ("gProductionONS" OR "Procedure_Variables"."Blender_Rinse"."ONS_Done") AND "Blender_Variables_Pers"."gBlenderStarted"
|
||||
IF ("gProductionONS" OR "Procedure_Variables"."Blender_Rinse"."ONS_Done") AND "Blender_Variables_Pers"."gBlenderStarted" THEN
|
||||
// RLO: ("gProductionONS" OR "Procedure_Variables"."Blender_Rinse"."ONS_Done") AND (NOT "Blender_Variables_Pers"."gBlenderStarted")
|
||||
IF ("gProductionONS" OR "Procedure_Variables"."Blender_Rinse"."ONS_Done") AND (NOT "Blender_Variables_Pers"."gBlenderStarted") THEN
|
||||
BlenderCtrl_ProdModeInit();
|
||||
END_IF;
|
||||
|
||||
// Network 27: Rinse ONS
|
||||
|
||||
// RLO: "HMI_Variables_Status"."System"."Blender_Prod_CIP"
|
||||
// PBox 26 - Passing bit: "M19002"
|
||||
// RLO: "M19002" AND "mDelayPowerOnTmr"
|
||||
"gRinseONS" := "M19002" AND "mDelayPowerOnTmr";
|
||||
// // PBox 26 - Passing memory bit: "M19002"
|
||||
// RLO: "M19002" AND (NOT "mDelayPowerOnTmr")
|
||||
"gRinseONS" := "M19002" AND (NOT "mDelayPowerOnTmr");
|
||||
|
||||
// Network 28: CIP ONS
|
||||
|
||||
// RLO: "gBlenderCIPMode"
|
||||
// PBox 26 - Passing bit: "M19003"
|
||||
// RLO: "M19003" AND "mDelayPowerOnTmr"
|
||||
"gCIPONS" := "M19003" AND "mDelayPowerOnTmr";
|
||||
// // PBox 26 - Passing memory bit: "M19003"
|
||||
// RLO: "M19003" AND (NOT "mDelayPowerOnTmr")
|
||||
"gCIPONS" := "M19003" AND (NOT "mDelayPowerOnTmr");
|
||||
|
||||
// Network 29: CIp Mode Init
|
||||
|
||||
|
@ -221,7 +216,7 @@ BEGIN
|
|||
|
||||
// Network 32: Tank Pressure Control
|
||||
|
||||
Prod Tank PressCtrl();
|
||||
Prod_Tank_PressCtrl();
|
||||
|
||||
// Network 33: Balaiage
|
||||
|
||||
|
@ -229,7 +224,7 @@ BEGIN
|
|||
|
||||
// Network 34: First Production
|
||||
|
||||
// ERROR: Call a bloque no soportado: ProcedureFirstProduction
|
||||
"FirstProduction_Data"();
|
||||
|
||||
// Network 35: CIP MAIN Calling
|
||||
|
||||
|
@ -257,14 +252,14 @@ BEGIN
|
|||
|
||||
// Network 41: Blend Procedure Data
|
||||
|
||||
// RLO: "mDelayPowerOnTmr"
|
||||
IF "mDelayPowerOnTmr" THEN
|
||||
// ERROR: Call a bloque no soportado: Procedure
|
||||
// RLO: (NOT "mDelayPowerOnTmr")
|
||||
IF (NOT "mDelayPowerOnTmr") THEN
|
||||
"Blender_Procedure Data"();
|
||||
END_IF;
|
||||
|
||||
// Network 42: Pneumatic Valve Control
|
||||
|
||||
Pneumatic Valve Ctrl();
|
||||
Pneumatic_Valve_Ctrl();
|
||||
|
||||
// Network 43: Pumps Control
|
||||
|
||||
|
@ -343,18 +338,18 @@ BEGIN
|
|||
|
||||
// Network 60: Blender Ctrl Command
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Simulation"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Simulation" THEN
|
||||
BlenderCtrl_MFM Command();
|
||||
// RLO: (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Simulation")
|
||||
IF (NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Simulation") THEN
|
||||
BlenderCtrl_MFM_Command();
|
||||
END_IF;
|
||||
|
||||
// Network 61: DP Global Diag
|
||||
|
||||
CPU_DP Global Diag();
|
||||
CPU_DP_Global_Diag();
|
||||
|
||||
// Network 62: Profibus
|
||||
|
||||
Profibus Network();
|
||||
Profibus_Network();
|
||||
|
||||
// Network 63: Valve Fault
|
||||
|
||||
|
@ -372,8 +367,8 @@ BEGIN
|
|||
// Network 66: Mod Copy Recipe
|
||||
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page"
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "mFP_Recip_Main_Page"
|
||||
"mAux_FP_M700_1" := "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "mFP_Recip_Main_Page";
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page" AND (NOT "mFP_Recip_Main_Page")
|
||||
"mAux_FP_M700_1" := "HMI_Variables_Cmd"."Recipe"."Main_Page" AND (NOT "mFP_Recip_Main_Page");
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page"
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "HMI_Variables_Cmd"."Recipe"."Edit"
|
||||
// RLO: "mAux_FP_M700_1"
|
||||
|
@ -382,7 +377,7 @@ BEGIN
|
|||
|
||||
// RLO: "AUX TRUE"
|
||||
IF "AUX TRUE" THEN
|
||||
// ERROR: Call a bloque no soportado: RecipeManagement - Prod
|
||||
"RecipeManagement_Data"();
|
||||
END_IF;
|
||||
|
||||
// Network 68: Recipe Calculation
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
"uid": "26",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -74,6 +75,7 @@
|
|||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -98,6 +100,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -142,6 +145,7 @@
|
|||
"uid": "24",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -162,19 +166,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -200,6 +205,7 @@
|
|||
"uid": "26",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -218,6 +224,7 @@
|
|||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -242,6 +249,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -288,10 +296,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "22",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -304,6 +310,9 @@
|
|||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -313,6 +322,7 @@
|
|||
"uid": "25",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "23",
|
||||
|
@ -341,6 +351,7 @@
|
|||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -361,19 +372,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -395,6 +407,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
|
@ -403,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": {
|
||||
|
@ -441,10 +454,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "22",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -457,6 +468,9 @@
|
|||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -466,6 +480,7 @@
|
|||
"uid": "25",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "23",
|
||||
|
@ -494,6 +509,7 @@
|
|||
"uid": "30",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -514,19 +530,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -548,6 +565,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
|
@ -556,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": {
|
||||
|
@ -588,6 +606,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "28",
|
||||
|
@ -596,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": {
|
||||
|
@ -632,6 +651,7 @@
|
|||
"uid": "29",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -650,12 +670,16 @@
|
|||
"uid": "30",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"gBlenderRinseMode\""
|
||||
},
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -667,6 +691,7 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"type": "connection",
|
||||
|
@ -690,19 +715,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -723,19 +749,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -756,19 +783,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -794,6 +822,7 @@
|
|||
"uid": "26",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -812,6 +841,7 @@
|
|||
"uid": "27",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -836,6 +866,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -883,15 +914,16 @@
|
|||
"SrcType": "Type",
|
||||
"DestType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
|
||||
},
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -912,6 +944,7 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -959,13 +992,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "36",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "27",
|
||||
"scope": "TypedConstant",
|
||||
|
@ -978,6 +1006,12 @@
|
|||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "36",
|
||||
"source_pin": "eno"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -987,6 +1021,7 @@
|
|||
"uid": "38",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "28",
|
||||
|
@ -1008,6 +1043,7 @@
|
|||
"uid": "39",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "29",
|
||||
|
@ -1032,6 +1068,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "31",
|
||||
|
@ -1069,12 +1106,19 @@
|
|||
"uid": "41",
|
||||
"type": "PBox",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"bit": {
|
||||
"uid": "33",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"M19012\""
|
||||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_instruction_uid": "37",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -1084,6 +1128,7 @@
|
|||
"uid": "42",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "34",
|
||||
|
@ -1112,6 +1157,7 @@
|
|||
"uid": "32",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -1133,18 +1179,19 @@
|
|||
"SrcType": "Type",
|
||||
"DestType": "Type"
|
||||
},
|
||||
"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": {
|
||||
|
@ -1165,6 +1212,7 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
|
@ -1212,13 +1260,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "34",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "28",
|
||||
"scope": "TypedConstant",
|
||||
|
@ -1231,6 +1274,12 @@
|
|||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "34",
|
||||
"source_pin": "eno"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
|
@ -1243,6 +1292,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "30",
|
||||
|
@ -1289,15 +1339,16 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
|
||||
},
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
"uid": "26",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -68,13 +69,14 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 26: \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
"scl": "// RLO: \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "27",
|
||||
"uid": "27",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -90,7 +92,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 27: \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\""
|
||||
"scl": "// RLO: \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
|
@ -100,6 +102,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -145,6 +148,7 @@
|
|||
"uid": "24",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -157,7 +161,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 24: \"SLIM_Variables\".\"ResetHour\""
|
||||
"scl": "// RLO: \"SLIM_Variables\".\"ResetHour\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "25",
|
||||
|
@ -166,19 +170,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -205,6 +210,7 @@
|
|||
"uid": "26",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -217,13 +223,14 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 26: \"gBlenderBlending\""
|
||||
"scl": "// RLO: \"gBlenderBlending\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "27",
|
||||
"uid": "27",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -239,7 +246,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 27: \"gBlenderBlending\" AND \"CLK_1.0S\""
|
||||
"scl": "// RLO: \"gBlenderBlending\" AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
|
@ -249,6 +256,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -296,10 +304,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "22",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -312,6 +318,9 @@
|
|||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
|
@ -322,6 +331,7 @@
|
|||
"uid": "25",
|
||||
"type": "Coil_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "23",
|
||||
|
@ -351,6 +361,7 @@
|
|||
"uid": "27",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -372,19 +383,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -408,6 +420,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
|
@ -416,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": {
|
||||
|
@ -456,10 +469,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "22",
|
||||
"scope": "LiteralConstant",
|
||||
|
@ -472,6 +483,9 @@
|
|||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
|
@ -482,6 +496,7 @@
|
|||
"uid": "25",
|
||||
"type": "Coil_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "23",
|
||||
|
@ -511,6 +526,7 @@
|
|||
"uid": "30",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -532,19 +548,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -568,6 +585,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
|
@ -576,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": {
|
||||
|
@ -610,6 +628,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "28",
|
||||
|
@ -618,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": {
|
||||
|
@ -656,6 +675,7 @@
|
|||
"uid": "29",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -668,23 +688,27 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 29: \"gBlenderCIPMode\""
|
||||
"scl": "// RLO: \"gBlenderCIPMode\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "30",
|
||||
"uid": "30",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"gBlenderRinseMode\""
|
||||
},
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 30: \"gBlenderRinseMode\""
|
||||
"scl": "// RLO: \"gBlenderRinseMode\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "31",
|
||||
|
@ -693,6 +717,7 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"type": "connection",
|
||||
|
@ -717,19 +742,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -752,19 +778,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -787,19 +814,20 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"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": {
|
||||
|
@ -827,6 +855,7 @@
|
|||
"uid": "26",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -839,13 +868,14 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 26: \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
"scl": "// RLO: \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "27",
|
||||
"uid": "27",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
|
@ -861,7 +891,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 27: \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\""
|
||||
"scl": "// RLO: \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
|
@ -871,6 +901,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -919,15 +950,16 @@
|
|||
"SrcType": "Type",
|
||||
"DestType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningSeconds\""
|
||||
},
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
@ -949,6 +981,7 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "24",
|
||||
|
@ -997,13 +1030,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "36",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "27",
|
||||
"scope": "TypedConstant",
|
||||
|
@ -1016,6 +1044,12 @@
|
|||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "36",
|
||||
"source_pin": "eno"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
|
@ -1026,6 +1060,7 @@
|
|||
"uid": "38",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "28",
|
||||
|
@ -1041,13 +1076,14 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 38: \"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
"scl": "// RLO: \"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "39",
|
||||
"uid": "39",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "29",
|
||||
|
@ -1063,7 +1099,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 39: (\"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\""
|
||||
"scl": "// RLO: (\"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "40",
|
||||
|
@ -1073,6 +1109,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "31",
|
||||
|
@ -1111,22 +1148,31 @@
|
|||
"uid": "41",
|
||||
"type": "PBox_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"bit": {
|
||||
"uid": "33",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"M19012\""
|
||||
},
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Eq",
|
||||
"source_instruction_uid": "37",
|
||||
"source_pin": "out"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"M19012\" := ((\"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\"); // Update edge memory bit"
|
||||
"_edge_mem_update_scl": "\"M19012\" := (\"MOD60\" = DINT#0);",
|
||||
"scl": "// Logic moved to Coil 42"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "42",
|
||||
"uid": "42",
|
||||
"type": "Coil_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "34",
|
||||
|
@ -1142,7 +1188,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"mRunMin\" := ((\"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\") AND NOT \"M19012\";"
|
||||
"scl": "\"mRunMin\" := (\"MOD60\" = DINT#0) AND NOT \"M19012\";\\n\"M19012\" := (\"MOD60\" = DINT#0); // P_TRIG((\"MOD60\" = DINT#0)) (Mem update handled by consumer)"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1156,6 +1202,7 @@
|
|||
"uid": "32",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
|
@ -1168,7 +1215,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 32: \"mRunMin\""
|
||||
"scl": "// RLO: \"mRunMin\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "33",
|
||||
|
@ -1178,18 +1225,19 @@
|
|||
"SrcType": "Type",
|
||||
"DestType": "Type"
|
||||
},
|
||||
"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": {
|
||||
|
@ -1211,6 +1259,7 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "25",
|
||||
|
@ -1259,13 +1308,8 @@
|
|||
"template_values": {
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "34",
|
||||
"source_pin": "eno"
|
||||
},
|
||||
"in2": {
|
||||
"uid": "28",
|
||||
"scope": "TypedConstant",
|
||||
|
@ -1278,6 +1322,12 @@
|
|||
"scope": "LocalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"MOD60\""
|
||||
},
|
||||
"pre": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Mod",
|
||||
"source_instruction_uid": "34",
|
||||
"source_pin": "eno"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
|
@ -1291,6 +1341,7 @@
|
|||
"Card": "Cardinality",
|
||||
"SrcType": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in2": {
|
||||
"uid": "30",
|
||||
|
@ -1338,15 +1389,16 @@
|
|||
"template_values": {
|
||||
"Card": "Cardinality"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"in": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Blender_Variables_Pers\".\"gRunningMaintHour\""
|
||||
},
|
||||
"en": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
|
|
@ -30,18 +30,23 @@ BEGIN
|
|||
|
||||
// Network 1: Seconds
|
||||
|
||||
// RLO: "Procedure_Variables"."Blender_Run"."Running"
|
||||
// RLO: "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S"
|
||||
IF "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S" THEN
|
||||
"Blender_Variables_Pers"."gSLIM_Sec" := "Blender_Variables_Pers"."gSLIM_Sec" + 1;
|
||||
END_IF;
|
||||
|
||||
// Network 2: Reset Hours
|
||||
|
||||
// RLO: "SLIM_Variables"."ResetHour"
|
||||
IF "SLIM_Variables"."ResetHour" THEN
|
||||
"Blender_Variables_Pers"."gSLIM_Sec" := 0;
|
||||
END_IF;
|
||||
|
||||
// Network 3: Seconds Counter
|
||||
|
||||
// RLO: "gBlenderBlending"
|
||||
// RLO: "gBlenderBlending" AND "CLK_1.0S"
|
||||
IF "gBlenderBlending" AND "CLK_1.0S" THEN
|
||||
"Blender_Variables_Pers"."gProdSec" := "Blender_Variables_Pers"."gProdSec" + 1;
|
||||
END_IF;
|
||||
|
@ -76,6 +81,8 @@ BEGIN
|
|||
|
||||
// Network 8: Counter reset
|
||||
|
||||
// RLO: "gBlenderCIPMode"
|
||||
// RLO: "gBlenderRinseMode"
|
||||
IF "gBlenderCIPMode" OR "gBlenderRinseMode" THEN
|
||||
"Blender_Variables_Pers"."gProdSec" := 0;
|
||||
"Blender_Variables_Pers"."gProdMin" := 0;
|
||||
|
@ -87,6 +94,8 @@ BEGIN
|
|||
|
||||
// Network 9: Running Seconds
|
||||
|
||||
// RLO: "Procedure_Variables"."Blender_Run"."Running"
|
||||
// RLO: "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S"
|
||||
IF "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S" THEN
|
||||
"Blender_Variables_Pers"."gRunningSeconds" := "Blender_Variables_Pers"."gRunningSeconds" + 1;
|
||||
END_IF;
|
||||
|
@ -95,14 +104,17 @@ BEGIN
|
|||
|
||||
"I_DIRunning_sec" := "Blender_Variables_Pers"."gRunningSeconds";
|
||||
"MOD60" := "I_DIRunning_sec" MOD DINT#60;
|
||||
// RLO: "MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running"
|
||||
// RLO: ("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S"
|
||||
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;
|
||||
"M19012" := (("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S"); // Update edge memory bit
|
||||
"mRunMin" := (("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S") AND NOT "M19012";
|
||||
// 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
|
||||
|
||||
// RLO: "mRunMin"
|
||||
IF "mRunMin" THEN
|
||||
"I_DIRunning_min" := "Blender_Variables_Pers"."gRunningMinutes";
|
||||
END_IF;
|
217
TestLAD.xml
217
TestLAD.xml
|
@ -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,40 +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="Clock_5Hz" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<Part Name="Contact" UId="23" />
|
||||
<Part Name="Coil" UId="24" />
|
||||
</Parts>
|
||||
<Wires>
|
||||
<Wire UId="25">
|
||||
<Powerrail />
|
||||
<NameCon UId="23" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="26">
|
||||
<IdentCon UId="21" />
|
||||
<NameCon UId="23" Name="operand" />
|
||||
</Wire>
|
||||
<Wire UId="27">
|
||||
<NameCon UId="23" Name="out" />
|
||||
<NameCon UId="24" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="28">
|
||||
<IdentCon UId="22" />
|
||||
<NameCon UId="24" Name="operand" />
|
||||
</Wire>
|
||||
</Wires>
|
||||
</FlgNet></NetworkSource>
|
||||
<NetworkSource />
|
||||
<ProgrammingLanguage>LAD</ProgrammingLanguage>
|
||||
</AttributeList>
|
||||
<ObjectList>
|
||||
|
@ -157,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">
|
||||
|
@ -206,35 +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="Clock_5Hz" />
|
||||
<Component Name="HMI_PID" />
|
||||
<Component Name="PPM303" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<Part Name="Contact" UId="23">
|
||||
<Negated Name="operand" />
|
||||
<Access Scope="LocalVariable" UId="23">
|
||||
<Symbol>
|
||||
<Component Name="Block_Move_Err" />
|
||||
</Symbol>
|
||||
</Access>
|
||||
<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>
|
||||
<Part Name="Coil" UId="24" />
|
||||
</Parts>
|
||||
<Wires>
|
||||
<Wire UId="25">
|
||||
<Powerrail />
|
||||
<NameCon UId="23" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="26">
|
||||
<IdentCon UId="21" />
|
||||
<NameCon UId="23" Name="operand" />
|
||||
</Wire>
|
||||
<Wire UId="27">
|
||||
<NameCon UId="23" Name="out" />
|
||||
<NameCon UId="24" Name="in" />
|
||||
<Powerrail />
|
||||
<NameCon UId="25" Name="in" />
|
||||
</Wire>
|
||||
<Wire UId="28">
|
||||
<IdentCon UId="21" />
|
||||
<NameCon UId="25" Name="operand" />
|
||||
</Wire>
|
||||
<Wire UId="29">
|
||||
<NameCon UId="25" Name="out" />
|
||||
<NameCon UId="26" Name="en" />
|
||||
</Wire>
|
||||
<Wire UId="30">
|
||||
<IdentCon UId="22" />
|
||||
<NameCon UId="24" Name="operand" />
|
||||
<NameCon UId="26" Name="SRCBLK" />
|
||||
</Wire>
|
||||
<Wire UId="31">
|
||||
<NameCon UId="26" Name="RET_VAL" />
|
||||
<IdentCon UId="23" />
|
||||
</Wire>
|
||||
<Wire UId="32">
|
||||
<NameCon UId="26" Name="DSTBLK" />
|
||||
<IdentCon UId="24" />
|
||||
</Wire>
|
||||
</Wires>
|
||||
</FlgNet></NetworkSource>
|
||||
|
@ -292,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">
|
||||
|
@ -335,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 />
|
||||
|
|
|
@ -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,110 +42,72 @@
|
|||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "Clock Bit",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "23",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Clock Bit",
|
||||
"title": "Filler Head",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"instruction_uid": "25",
|
||||
"uid": "25",
|
||||
"type": "Contact",
|
||||
"template_values": {},
|
||||
"negated_pins": {
|
||||
"operand": true
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
"name": "\"AUX FALSE\""
|
||||
},
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {}
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil",
|
||||
"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": "23",
|
||||
"source_instruction_uid": "25",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"SRCBLK": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
"name": "\"HMI_PID\".\"PPM303\""
|
||||
}
|
||||
},
|
||||
"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\""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "",
|
||||
"comment": "",
|
||||
"logic": [],
|
||||
"error": "FlgNet not found"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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,114 +42,74 @@
|
|||
]
|
||||
},
|
||||
"networks": [
|
||||
{
|
||||
"id": "9",
|
||||
"title": "Clock Bit",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO: \"Clock_10Hz\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "23",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"Clock_5Hz\" := \"Clock_10Hz\";"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1A",
|
||||
"title": "Clock Bit",
|
||||
"title": "Filler Head",
|
||||
"comment": "",
|
||||
"logic": [
|
||||
{
|
||||
"instruction_uid": "23",
|
||||
"uid": "23",
|
||||
"instruction_uid": "25",
|
||||
"uid": "25",
|
||||
"type": "Contact_scl",
|
||||
"template_values": {},
|
||||
"negated_pins": {
|
||||
"operand": true
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
},
|
||||
"operand": {
|
||||
"uid": "21",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_10Hz\""
|
||||
"name": "\"AUX FALSE\""
|
||||
},
|
||||
"in": {
|
||||
"type": "powerrail"
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO: (NOT \"Clock_10Hz\")"
|
||||
"scl": "// RLO: \"AUX FALSE\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "24",
|
||||
"uid": "24",
|
||||
"type": "Coil_scl",
|
||||
"template_values": {},
|
||||
"instruction_uid": "26",
|
||||
"uid": "26",
|
||||
"type": "BLKMOV_scl",
|
||||
"template_values": {
|
||||
"blk_type": "Type"
|
||||
},
|
||||
"negated_pins": {},
|
||||
"inputs": {
|
||||
"in": {
|
||||
"en": {
|
||||
"type": "connection",
|
||||
"source_instruction_type": "Contact",
|
||||
"source_instruction_uid": "23",
|
||||
"source_instruction_uid": "25",
|
||||
"source_pin": "out"
|
||||
},
|
||||
"operand": {
|
||||
"SRCBLK": {
|
||||
"uid": "22",
|
||||
"scope": "GlobalVariable",
|
||||
"type": "variable",
|
||||
"name": "\"Clock_5Hz\""
|
||||
"name": "\"HMI_PID\".\"PPM303\""
|
||||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"Clock_5Hz\" := (NOT \"Clock_10Hz\");"
|
||||
"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\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"scl": "IF \"AUX FALSE\" THEN\n \"Block_Move_Err\" := BLKMOV(SRCBLK := \"HMI_PID\".\"PPM303\", DSTBLK => \"Filler_Head_Variables\".\"FillerHead\"); // ADVERTENCIA: BLKMOV usado directamente, probablemente no compile!\nEND_IF;"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2B",
|
||||
"title": "",
|
||||
"comment": "",
|
||||
"logic": [],
|
||||
"error": "FlgNet not found"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -16,20 +16,22 @@ 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"
|
||||
"Clock_5Hz" := "Clock_10Hz";
|
||||
|
||||
// Network 2: Clock Bit
|
||||
|
||||
// RLO: (NOT "Clock_10Hz")
|
||||
"Clock_5Hz" := (NOT "Clock_10Hz");
|
||||
|
||||
// Network 3:
|
||||
// RLO: "AUX FALSE"
|
||||
IF "AUX FALSE" THEN
|
||||
"Block_Move_Err" := BLKMOV(SRCBLK := "HMI_PID"."PPM303", DSTBLK => "Filler_Head_Variables"."FillerHead"); // ADVERTENCIA: BLKMOV usado directamente, probablemente no compile!
|
||||
END_IF;
|
||||
|
||||
END_FUNCTION_BLOCK
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// Block Name (Original): TestLAD
|
||||
// Block Number: 2
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "TestLAD"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Clock Bit
|
||||
|
||||
"Clock_5Hz" := "Clock_10Hz";
|
||||
|
||||
// Network 2: Clock Bit
|
||||
|
||||
"Clock_5Hz" := "Clock_10Hz";
|
||||
|
||||
// Network 3:
|
||||
|
||||
END_FUNCTION_BLOCK
|
|
@ -0,0 +1,170 @@
|
|||
# LAD-to-SCL Conversion Pipeline: Documentación de Referencia
|
||||
|
||||
## 1. Visión General
|
||||
|
||||
Este documento describe un pipeline de scripts de Python diseñado para convertir bloques de función o funciones (FC/FB) escritos en Ladder Logic (LAD) desde archivos XML de TIA Portal Openness a un código SCL (Structured Control Language) semánticamente equivalente.
|
||||
|
||||
El proceso se divide en tres etapas principales, cada una manejada por un script específico:
|
||||
|
||||
1. **XML a JSON Enriquecido (`x1_to_json.py`):** Parsea el XML de Openness, extrae la estructura lógica (incluyendo llamadas a FC/FB y temporizadores S5), conexiones explícitas e **infiere conexiones implícitas** (especialmente las habilitaciones EN) para crear un archivo JSON detallado. Mapea tipos de instrucción LAD/FBD (p.ej., `Se`, `NBox`) a nombres internos consistentes (p.ej., `TON_S5`, `N_TRIG`).
|
||||
2. **Procesamiento Semántico (`x2_process.py`):** Lee el JSON enriquecido y, de forma iterativa, traduce cada instrucción (usando los tipos mapeados) a su equivalente SCL, manejando dependencias, propagando el estado lógico (RLO), traduciendo temporizadores S5 a IEC, generando lógica de flancos y agrupando lógica paralela bajo bloques `IF`. El SCL generado se almacena *dentro* del propio JSON.
|
||||
3. **Generación de SCL Final (`x3_generate_scl.py`):** Lee el JSON completamente procesado y ensambla el código SCL final en un archivo `.scl` formateado, incluyendo declaraciones de variables (Input, Output, InOut, Temp, Stat - incluyendo instancias de temporizadores y bits de memoria de flancos) y el cuerpo del programa (`FUNCTION` o `FUNCTION_BLOCK`).
|
||||
|
||||
## 2. Etapas del Pipeline
|
||||
|
||||
### Etapa 1: XML a JSON Enriquecido (`x1_to_json.py`)
|
||||
|
||||
* **Propósito:** Transformar la compleja y a veces ambigua estructura XML de Openness en un formato JSON estructurado y más fácil de procesar, añadiendo información clave que está implícita en el LAD visual pero no siempre explícita en el XML.
|
||||
* **Entrada:** Archivo `.xml` exportado desde TIA Portal Openness para un FC o FB.
|
||||
* **Salida:** Archivo `_simplified.json`.
|
||||
* **Proceso Clave:**
|
||||
1. **Parseo XML:** Utiliza `lxml` para leer el archivo XML.
|
||||
2. **Extracción de Metadatos:** Obtiene nombre del bloque, número, lenguaje original, comentario del bloque. Detecta si es `SW.Blocks.FC` o `SW.Blocks.FB`.
|
||||
3. **Extracción de Interfaz:** Parsea las secciones `Input`, `Output`, `InOut`, `Temp`, `Constant`, `Return` para obtener la declaración de variables.
|
||||
4. **Parseo de Redes (`CompileUnit`):** Itera sobre cada red lógica.
|
||||
* **`parse_network`:**
|
||||
* **Parseo de Componentes:**
|
||||
* `Access`: Identifica variables globales/locales, constantes literales y tipadas (`parse_access`). Utiliza `get_symbol_name` para formatear nombres simbólicos con comillas (`"DB"."Var"`).
|
||||
* `Part`: Identifica instrucciones estándar LAD/FBD (`parse_part`). **Importante:** Detecta pines negados (`<Negated>`) y los almacena en `negated_pins`. **Mapea** nombres XML (`Se`, `Sd`, `PBox`, `NBox`, `RCoil`, `SCoil`, `SdCoil`) a tipos internos (`TON_S5`, `TONR_S5`, `P_TRIG`, `N_TRIG`, `R`, `S`, `SR`).
|
||||
* `Call`: Identifica llamadas a otros FCs o FBs (`parse_call`), extrayendo el nombre del bloque llamado, tipo (FC/FB) e información de instancia DB (`instance_db`) si aplica (formateado con comillas).
|
||||
* Crea `access_map` y `parts_and_calls_map` para referencia rápida por UID.
|
||||
* **Parseo de Conexiones (`Wire`):**
|
||||
* Construye `wire_connections`: Un mapa `(dest_uid, dest_pin) -> [(src_uid, src_pin), ...]`.
|
||||
* Construye `source_connections`: Un mapa `(src_uid, src_pin) -> [(dest_uid, dest_pin), ...]`.
|
||||
* **Construcción Lógica Inicial:** Crea una lista de diccionarios (`all_logic_steps`), uno por cada `Part` o `Call`, rellenando `inputs` y `outputs` **solo con las conexiones explícitas** encontradas en los `Wire`.
|
||||
* **Inferencia de Conexión `EN` (¡Paso Crucial!):**
|
||||
* Itera sobre los bloques funcionales (`Move`, `Add`, `Call`, `BLKMOV`, etc.) que *no* tienen una entrada `en` explícita definida después del paso anterior.
|
||||
* Utiliza una **heurística de búsqueda lineal hacia atrás** para encontrar la fuente de RLO más probable que precede a este bloque (la salida `out` de un bloque lógico como `Contact`/`O`/`Eq`/`P_TRIG`/`N_TRIG` o la salida `eno` de un bloque funcional anterior).
|
||||
* Si se encuentra una fuente inferida, **añade la conexión `en`** al diccionario `inputs` del bloque funcional actual. Esto enriquece el JSON con la dependencia lógica implícita.
|
||||
* **Ordenamiento:** Ordena las instrucciones en la lista `logic` final (generalmente por UID).
|
||||
5. **Escritura JSON:** Guarda la estructura de datos completa en el archivo `_simplified.json`.
|
||||
|
||||
### Etapa 2: Procesamiento Semántico (`x2_process.py`)
|
||||
|
||||
* **Propósito:** Traducir la lógica LAD/FBD (representada en el JSON enriquecido) a código SCL embebido, resolviendo dependencias entre instrucciones, generando lógica SCL equivalente (incluyendo manejo de flancos y temporizadores), y aplicando optimizaciones de agrupación `IF`.
|
||||
* **Entrada:** Archivo `_simplified.json` (generado por la Etapa 1).
|
||||
* **Salida:** Archivo `_simplified_processed.json`.
|
||||
* **Proceso Clave:**
|
||||
1. **Carga de JSON y Preparación:** Lee el JSON de entrada y reconstruye mapas de acceso por red. Inicializa el `scl_map` global (o por red).
|
||||
2. **Bucle Iterativo:** Repite los siguientes pasos hasta que no se realicen cambios en un pase completo o se alcance un límite máximo de pases (`max_passes`).
|
||||
* **Fase 1: Procesadores Base:**
|
||||
* Itera sobre cada instrucción en cada red.
|
||||
* Si la instrucción no ha sido procesada (`_scl` o `_error`) ni agrupada (`grouped`), busca el procesador adecuado (`process_xxx`) basado en su `type` (usando los tipos mapeados como `TON_S5`, `P_TRIG`, etc.).
|
||||
* **`process_xxx` (Ejecución):**
|
||||
* Llama a `get_scl_representation` para obtener el SCL de sus pines de entrada, buscándolos en `scl_map` o directamente en `access_map`. `get_scl_representation` ahora **convierte constantes S5T# a T#**.
|
||||
* Si alguna dependencia no está resuelta (devuelve `None`), el procesador retorna `False`.
|
||||
* Si las dependencias están resueltas:
|
||||
* **Generadores RLO (`Contact`, `O`, `Eq`, `P_TRIG`, `N_TRIG`):** Calculan la expresión booleana SCL resultante y la almacenan en `scl_map` bajo la clave `(network_id, instr_uid, 'out')`. `P_TRIG`/`N_TRIG` generan lógica explícita de flancos y la llamada para actualizar el bit de memoria (`stat_... := CLK;`). Guardan comentarios/lógica en `instruction['scl']`.
|
||||
* **Bloques Funcionales (`Move`, `Add`, `Convert`, `Mod`, `BLKMOV`, `Call`):**
|
||||
* Obtienen la condición `EN` (explícita o inferida).
|
||||
* Generan el código SCL *core* (la asignación, cálculo o llamada). `process_call` ahora usa correctamente `instance_db` para FBs. `process_blkmov` traduce a `DST := SRC;` (con advertencia sobre tipos).
|
||||
* Generan el SCL final, **envolviendo el core en `IF en_scl THEN ... END_IF;`** si `en_scl` no es `"TRUE"`.
|
||||
* Almacenan el SCL final en `instruction['scl']`.
|
||||
* Almacenan el nombre de la variable de salida/temporal (prefijado con `#` si es temporal) en `scl_map` para `out`/`out1`/`RET_VAL`.
|
||||
* Almacenan el `en_scl` en `scl_map` para `eno`.
|
||||
* **Bobinas (`Coil`, `R`, `S`, `SR`):** Obtienen el RLO de entrada (`in`, o `S`/`R1` para `SR`), obtienen el operando destino, generan la asignación (`:= TRUE`/`:= FALSE`) o lógica `IF/ELSIF` envuelta en `IF RLO THEN ...` si aplica, y la guardan en `instruction['scl']`.
|
||||
* **Temporizadores (`TON_S5`, `TONR_S5`):** Generan una llamada a un bloque IEC (`TON`/`TONR`) usando un nombre de instancia (`stat_timer_...`). Parsean el valor `PT` (T#...). Mapean `Q` y `ET` a la instancia (`Instance.Q`, `Instance.ET`) en `scl_map`. Almacenan la llamada en `instruction['scl']`.
|
||||
* Marcan la instrucción como procesada añadiendo `_scl` a `instruction['type']`.
|
||||
* Retornan `True`.
|
||||
* Se registra si hubo algún cambio en esta fase (`made_change_in_base_pass`).
|
||||
* **Fase 2: Agrupación de IFs (`process_group_ifs`):**
|
||||
* Itera sobre las instrucciones *ya procesadas* (`_scl`) que son generadoras de condición (`Contact`, `O`, `Eq`, `P_TRIG`, `N_TRIG`, etc.).
|
||||
* Obtiene la `condition_scl` de `scl_map`.
|
||||
* Busca todos los bloques funcionales, bobinas o temporizadores (`Move_scl`, `Add_scl`, `Coil_scl`, `TON_S5_scl`, etc.) cuyo pin de habilitación (`en`, `in`, `s`) esté conectado a la salida `out` de esta instrucción generadora.
|
||||
* Si encuentra **más de uno**:
|
||||
* Extrae el código *core* (lo que está dentro del `IF...END_IF;` si existe, o el código completo si no) de cada consumidor.
|
||||
* Construye un **único bloque `IF condition_scl THEN ... END_IF;`** que contiene todos los cores extraídos, indentados.
|
||||
* **Sobrescribe** el campo `scl` de la instrucción *generadora de condición* con este nuevo bloque `IF` agrupado.
|
||||
* Marca cada instrucción consumidora con `grouped = True` y cambia su `scl` a un comentario (`GROUPED_COMMENT`) para evitar que `x3_generate_scl.py` lo use.
|
||||
* Se registra si hubo algún cambio en esta fase (`made_change_in_group_pass`).
|
||||
* **Condición de Salida:** El bucle termina si `made_change_in_base_pass` y `made_change_in_group_pass` son ambos `False`.
|
||||
3. **Verificación Final:** Comprueba si quedaron instrucciones sin procesar, sin agrupar y sin errores, e informa al usuario.
|
||||
4. **Escritura JSON:** Guarda el JSON modificado (con SCL embebido y marcas de agrupación) en el archivo `_simplified_processed.json`.
|
||||
|
||||
### Etapa 3: Generación de SCL Final (`x3_generate_scl.py`)
|
||||
|
||||
* **Propósito:** Ensamblar un archivo `.scl` completo y formateado a partir del JSON procesado.
|
||||
* **Entrada:** Archivo `_simplified_processed.json` (generado por la Etapa 2).
|
||||
* **Salida:** Archivo `.scl`.
|
||||
* **Proceso Clave:**
|
||||
1. **Carga de JSON:** Lee el archivo JSON procesado.
|
||||
2. **Detección de Variables y Tipo de Bloque:**
|
||||
* Escanea el SCL generado en busca de variables `#_temp_...` y `stat_...`.
|
||||
* Identifica los tipos de las variables `stat_...` (Bool, TON, TONR) según sus nombres (`stat_nbox_mem...`, `stat_timer_Se...`, etc.).
|
||||
* Determina si el bloque debe ser `FUNCTION_BLOCK` (si hay variables `STAT` o `TEMP`) o `FUNCTION`.
|
||||
3. **Generación de Cabecera:** Escribe el encabezado del bloque (`FUNCTION_BLOCK name` o `FUNCTION name`, `VERSION`, etc.). Utiliza `format_variable_name` (la versión corregida) para el nombre del bloque.
|
||||
4. **Generación de Declaraciones VAR:**
|
||||
* Escribe las secciones `VAR_INPUT`, `VAR_OUTPUT`, `VAR_IN_OUT` usando `format_variable_name` para los nombres de las variables de la interfaz.
|
||||
* **Escribe `VAR_STAT`:** Declara las variables `stat_...` detectadas con sus tipos inferidos (Bool, TON, TONR) y nombres entre comillas.
|
||||
* **Escribe `VAR_TEMP`:** Declara las variables `#_temp_...` detectadas (declaradas como `"_temp_..."` sin el `#` pero con comillas) y las variables de la sección `Temp` de la interfaz. Utiliza inferencia de tipo básica para las variables `#_temp_...`.
|
||||
5. **Generación del Cuerpo (`BEGIN`/`END_FUNCTION_BLOCK` o `END_FUNCTION`):**
|
||||
* Itera sobre las `networks` en el JSON.
|
||||
* Añade comentarios de red.
|
||||
* Itera sobre la `logic` de cada red.
|
||||
* Para cada `instruction`:
|
||||
* **Verifica el flag `grouped`:** Si `instruction.get('grouped', False)` es `True`, **ignora** esta instrucción.
|
||||
* Si no está agrupada, obtiene el valor del campo `scl`.
|
||||
* **Limpia comentarios internos:** Elimina comentarios informativos específicos (`// RLO:`, `// Comparison:`, `// Logic O:`, `// N/P_TRIG Output Logic:`) si son la única parte de la línea, pero conserva los comentarios de actualización de memoria de flancos, errores y agrupación.
|
||||
* Indenta y añade las líneas del SCL resultante al output.
|
||||
* Añade líneas en blanco entre redes si contienen código.
|
||||
6. **Escritura de Archivo:** Escribe el string SCL completo al archivo `.scl`.
|
||||
|
||||
## 3. Cómo Extender para Nuevas Instrucciones LAD/FBD
|
||||
|
||||
Añadir soporte para un nuevo tipo de instrucción (p.ej., un comparador `GT`, una función matemática `SQRT`, o un temporizador IEC `TP`) requiere modificar los scripts `x1_to_json.py` y `x2_process.py`.
|
||||
|
||||
**Pasos:**
|
||||
|
||||
1. **Analizar el XML:** Exporta un bloque simple que use la nueva instrucción y examina el XML de Openness. Identifica:
|
||||
* Si se representa como `<Part Name="NombreInstruccion">` o `<Call Name="NombreInstruccion">`.
|
||||
* Sus pines de entrada y salida (`NameCon`/`IdentCon` en los `Wire`).
|
||||
* Cualquier atributo o `TemplateValue` relevante.
|
||||
* Si tiene pines negados (`<Negated>`).
|
||||
|
||||
2. **Modificar `x1_to_json.py` (`parse_part` o `parse_call` y `parse_network`):**
|
||||
* **Parseo:** Asegúrate de que `parse_part` o `parse_call` capture correctamente la nueva instrucción.
|
||||
* **Mapeo de Tipo:** Si el nombre XML no es ideal (como `Se`), mapéalo a un nombre interno consistente en `parse_part` (p.ej., si fuera un temporizador IEC TP, podrías mapear `TPartName` -> `TP_IEC`).
|
||||
* **Clasificación:** Decide si la nueva instrucción es un `functional_block_type` (necesita inferencia EN?) o un `rlo_generator`. Actualiza estas listas en `parse_network` si es necesario.
|
||||
* **Inferencia EN:** Revisa si la lógica de inferencia EN en `parse_network` necesita ajustes.
|
||||
* **Pines:** Asegúrate de que sus pines de entrada/salida esperados estén en `possible_input_pins` / `possible_output_pins` en `parse_network`.
|
||||
|
||||
3. **Modificar `x2_process.py` (continuación):**
|
||||
* **Lógica SCL (continuación):**
|
||||
* ...
|
||||
* Almacena el SCL final en `instruction['scl']`.
|
||||
* Actualiza `instruction['type']` con el sufijo `_scl`.
|
||||
* **Actualiza `scl_map`:** Añade entradas para los pines de salida (`out`, `Q`, etc.) con su representación SCL (puede ser un nombre de variable temporal prefijado con `#`, el resultado de una expresión, o el acceso a un miembro de instancia como `"Instance".Q`). Añade la entrada para `eno` si el bloque lo tiene (generalmente `scl_map[key_eno] = en_scl`).
|
||||
* Retorna `True`.
|
||||
* **Añadir a la Lista:** Inserta la nueva función `process_nombre_instruccion` en la lista `base_processors_list` en el orden de prioridad correcto (generalmente, generadores de valores/condiciones antes que consumidores, y las llamadas (`process_call`) al final o cerca del final). Actualiza el `processor_map` si es necesario (especialmente si manejas tipos como `Call_FC`, `Call_FB`).
|
||||
* **Agrupación:** Considera si este nuevo bloque debería ser parte de la lógica de agrupación (¿es un bloque funcional, bobina o temporizador que puede ser habilitado en paralelo?). Si es así, añádelo a la lista `groupable_types_original` en `process_group_ifs`. El código de agrupación existente debería funcionar si el procesador del nuevo bloque genera correctamente la estructura `IF EN THEN ... END_IF;` (o código simple si EN=TRUE).
|
||||
|
||||
4. **Modificar `x3_generate_scl.py`:**
|
||||
* **Declaraciones STAT:** Si la nueva instrucción introduce la necesidad de un nuevo tipo de variable estática (p.ej., un tipo de datos específico para un contador, o un nuevo tipo de instancia de FB IEC), necesitarás:
|
||||
* Añadir una nueva expresión regular (`stat_pattern_xxx`) para detectar el nombre de la instancia/variable estática generada por tu nuevo procesador en `x2_process.py`.
|
||||
* Actualizar el bucle de detección para que use esta nueva regex y almacene el nombre y el tipo SCL correcto (`MyCounterType`, `IEC_Counter`, etc.) en el diccionario `stat_vars`.
|
||||
* La lógica existente en `generate_scl` que escribe la sección `VAR_STAT` usará esta información para declarar la variable correctamente.
|
||||
* **Declaraciones TEMP:** Si la nueva instrucción genera variables temporales con un patrón específico o requiere un tipo de dato específico que pueda ser inferido, puedes mejorar la lógica de inferencia de tipo en la sección `VAR_TEMP`.
|
||||
* **Limpieza de Comentarios:** Si el nuevo procesador genera comentarios internos específicos que no quieres en el SCL final, ajusta la lógica de filtrado en la sección de generación del cuerpo del bloque.
|
||||
|
||||
5. **Probar:**
|
||||
* Crea un archivo XML de prueba simple que use la nueva instrucción en diferentes contextos (con entradas/salidas conectadas, con EN explícito/implícito, negaciones si aplica).
|
||||
* Ejecuta el pipeline completo (`x1_to_json.py`, `x2_process.py`, `x3_generate_scl.py`).
|
||||
* **Verifica `_simplified.json`:** Asegúrate de que `x1` parseó correctamente la instrucción, mapeó su tipo, identificó sus conexiones y realizó la inferencia EN si era necesario.
|
||||
* **Verifica `_simplified_processed.json`:** Comprueba que `x2` ejecutó tu nuevo procesador, generó el SCL esperado en el campo `scl`, marcó el tipo con `_scl`, y actualizó el `scl_map` correctamente para sus salidas. Verifica si la agrupación `IF` funcionó como se esperaba si la instrucción era parte de lógica paralela.
|
||||
* **Verifica el archivo `.scl`:** Confirma que `x3` generó el SCL final correctamente, incluyendo las declaraciones necesarias (STAT/TEMP) y el código SCL de la instrucción (indentado y sin comentarios no deseados). Asegúrate de que no haya errores de sintaxis SCL obvios.
|
||||
* **Importar en TIA Portal (Opcional pero Recomendado):** Intenta importar el archivo SCL generado en un proyecto de TIA Portal para validar la sintaxis y la estructura del bloque.
|
||||
|
||||
## 4. Futuras Mejoras y Consideraciones
|
||||
|
||||
* **Manejo de Tipos de Datos:** Implementar un seguimiento y conversión de tipos más robusto. Inferir tipos para variables temporales de forma más precisa. Usar funciones de conversión SCL explícitas (`INT_TO_DINT`, etc.) donde sea necesario, posiblemente requiriendo información de tipo adicional en el JSON.
|
||||
* **Lógica de Flancos/Temporizadores:** Asegurar que la traducción de temporizadores S5 y la lógica de flancos generada sea completamente compatible con los bloques IEC estándar (`TON`, `TOF`, `TP`, `TONR`, `R_TRIG`, `F_TRIG`). Considerar la necesidad de declarar instancias de `R_TRIG`/`F_TRIG` en `VAR_STAT` en lugar de generar lógica explícita.
|
||||
* **Soporte para FBs:** Mejorar el manejo de parámetros InOut y Return para llamadas a FC/FB. Potencialmente, requerir información de la interfaz del bloque llamado (parseando su propio XML o desde una biblioteca) para generar llamadas SCL más precisas.
|
||||
* **Optimización SCL:** Explorar más optimizaciones SCL más allá de la agrupación de IFs (p.ej., simplificación de expresiones booleanas complejas, propagación de constantes).
|
||||
* **Estructuras LAD Complejas:** La inferencia de EN actual (búsqueda lineal hacia atrás) es simple. Para manejar bifurcaciones (`Branch`), uniones (`Merge`) y saltos (`JMP`) complejos de forma robusta, `x1_to_json.py` necesitaría realizar un análisis de flujo de datos/control más sofisticado para determinar las dependencias lógicas correctas antes de generar el JSON.
|
||||
* **Manejo de Errores:** Mejorar el reporte de errores con más contexto (nombre de red, UID, tipo de instrucción). Añadir más validaciones en cada etapa.
|
||||
* **Interfaz Gráfica/Configuración:** Crear una interfaz más amigable o archivos de configuración para gestionar el proceso, seleccionar archivos y configurar opciones (p.ej., idioma por defecto, nivel de log).
|
||||
* **Soporte para otros lenguajes (FBD/STL):** Extender el parser `x1_to_json.py` y los procesadores en `x2_process.py` para manejar otros lenguajes de origen, lo cual requeriría entender sus respectivas representaciones XML en Openness.
|
||||
|
||||
## 5. Conclusión
|
||||
|
||||
Este pipeline proporciona una base funcional para la conversión automática de LAD a SCL desde archivos TIA Portal Openness XML. La clave de su funcionamiento es la **separación de responsabilidades**: `x1` enriquece el modelo de datos con información implícita, `x2` realiza la traducción semántica iterativa y la optimización de agrupación, y `x3` ensambla el archivo SCL final. Al añadir procesadores específicos para cada tipo de instrucción LAD/FBD y refinar la lógica de inferencia y generación, la cobertura y calidad de la conversión pueden ser extendidas significativamente. La estructura modular facilita la incorporación de soporte para nuevas instrucciones y futuras mejoras.
|
|
@ -0,0 +1,687 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import os
|
||||
from lxml import etree
|
||||
import traceback
|
||||
from collections import defaultdict
|
||||
|
||||
# --- Namespaces ---
|
||||
ns = {
|
||||
"iface": "http://www.siemens.com/automation/Openness/SW/Interface/v5",
|
||||
"flg": "http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4",
|
||||
}
|
||||
|
||||
|
||||
# --- Helper Functions ---
|
||||
# get_multilingual_text, get_symbol_name, parse_access - No changes needed from previous corrected version
|
||||
def get_multilingual_text(element, default_lang="en-US", fallback_lang="it-IT"):
|
||||
if element is None:
|
||||
return ""
|
||||
try:
|
||||
# Try default language first
|
||||
xpath_expr_default = (
|
||||
f".//iface:MultilingualTextItem[iface:Culture='{default_lang}']/iface:Text"
|
||||
)
|
||||
text_items = element.xpath(xpath_expr_default, namespaces=ns)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
|
||||
# Try fallback language
|
||||
xpath_expr_fallback = (
|
||||
f".//iface:MultilingualTextItem[iface:Culture='{fallback_lang}']/iface:Text"
|
||||
)
|
||||
text_items = element.xpath(xpath_expr_fallback, namespaces=ns)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
|
||||
# Try any language if specific ones fail
|
||||
xpath_expr_any = ".//iface:MultilingualTextItem/iface:Text"
|
||||
text_items = element.xpath(xpath_expr_any, namespaces=ns)
|
||||
if text_items and text_items[0].text is not None:
|
||||
return text_items[0].text.strip()
|
||||
|
||||
return "" # No text found
|
||||
except Exception as e:
|
||||
# print(f"Advertencia: Error extrayendo MultilingualText: {e}") # Reduced verbosity
|
||||
return ""
|
||||
|
||||
|
||||
def get_symbol_name(symbol_element):
|
||||
"""Extracts the full symbolic name, adding quotes around each component."""
|
||||
if symbol_element is None:
|
||||
return None
|
||||
try:
|
||||
# Namespace might be missing on Component, use local-name()
|
||||
components = symbol_element.xpath("./*[local-name()='Component']/@Name")
|
||||
# Ensure quotes are added correctly
|
||||
return ".".join(f'"{c}"' for c in components) if components else None
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Excepción en get_symbol_name: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def parse_access(access_element):
|
||||
"""Parses Access elements (variables, constants)."""
|
||||
if access_element is None:
|
||||
return None
|
||||
uid = access_element.get("UId")
|
||||
scope = access_element.get(
|
||||
"Scope"
|
||||
) # GlobalVariable, LocalVariable, LiteralConstant, TypedConstant etc.
|
||||
info = {"uid": uid, "scope": scope, "type": "unknown_access"} # Default type
|
||||
|
||||
symbol = access_element.xpath("./*[local-name()='Symbol']")
|
||||
constant = access_element.xpath("./*[local-name()='Constant']")
|
||||
# Add check for ConstantValue tag directly under Access (sometimes happens for literals)
|
||||
const_val_direct = access_element.xpath("./*[local-name()='ConstantValue']/text()")
|
||||
|
||||
if symbol:
|
||||
info["type"] = "variable"
|
||||
info["name"] = get_symbol_name(symbol[0])
|
||||
if info["name"] is None:
|
||||
info["type"] = "error_parsing_symbol"
|
||||
print(f"Error: No se pudo parsear nombre símbolo Access UID={uid}")
|
||||
elif constant:
|
||||
info["type"] = "constant"
|
||||
const_type_elem = constant[0].xpath("./*[local-name()='ConstantType']")
|
||||
const_val_elem = constant[0].xpath("./*[local-name()='ConstantValue']")
|
||||
info["datatype"] = (
|
||||
const_type_elem[0].text.strip()
|
||||
if const_type_elem and const_type_elem[0].text
|
||||
else "Unknown"
|
||||
)
|
||||
info["value"] = (
|
||||
const_val_elem[0].text.strip()
|
||||
if const_val_elem and const_val_elem[0].text
|
||||
else None
|
||||
)
|
||||
|
||||
if info["value"] is None:
|
||||
info["type"] = "error_parsing_constant"
|
||||
print(f"Error: Constante sin valor Access UID={uid}")
|
||||
# Handle S5Time specifically - store its original format
|
||||
elif info["datatype"] == "Unknown" and scope == "TypedConstant":
|
||||
if info["value"].upper().startswith("S5T#"):
|
||||
info["datatype"] = "S5Time" # Mark as S5Time, value remains S5T#...
|
||||
# Add other typed constant checks if necessary (e.g., C#, P#)
|
||||
|
||||
elif const_val_direct and scope == "LiteralConstant":
|
||||
info["type"] = "constant"
|
||||
info["value"] = const_val_direct[0].strip()
|
||||
# Infer datatype for literals
|
||||
val_lower = info["value"].lower()
|
||||
if val_lower in ["true", "false"]:
|
||||
info["datatype"] = "Bool"
|
||||
elif info["value"].isdigit() or (
|
||||
info["value"].startswith("-") and info["value"][1:].isdigit()
|
||||
):
|
||||
info["datatype"] = "Int" # Could be DInt etc, Int is safe default
|
||||
elif "." in info["value"] or "e" in val_lower:
|
||||
try:
|
||||
float(info["value"])
|
||||
info["datatype"] = "Real" # Could be LReal
|
||||
except ValueError:
|
||||
info["datatype"] = "String" # If float conversion fails
|
||||
else:
|
||||
info["datatype"] = "String" # Default literal type
|
||||
|
||||
# If still unknown, log warning
|
||||
if info["type"] == "unknown_access":
|
||||
# Don't warn for Constant scope as it might be handled later
|
||||
if scope != "Constant":
|
||||
print(
|
||||
f"Advertencia: Access UID={uid} scope={scope} no es Symbol ni Constant reconocible."
|
||||
)
|
||||
|
||||
# Ensure variable has a name
|
||||
if info["type"] == "variable" and not info.get("name"):
|
||||
print(f"Error Interno: parse_access var sin nombre UID {uid}.")
|
||||
info["type"] = "error_no_name"
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def parse_part(part_element):
|
||||
"""Parses Part elements (standard instructions), extracting UID, name, template values, and negated pins."""
|
||||
if part_element is None:
|
||||
return None
|
||||
uid = part_element.get("UId")
|
||||
name_orig = part_element.get("Name") # Instruction type (e.g., Contact, Coil, Move)
|
||||
if not uid or not name_orig:
|
||||
print(
|
||||
f"Error: Part sin UID o Name: {etree.tostring(part_element, encoding='unicode')}"
|
||||
)
|
||||
return None
|
||||
|
||||
template_values = {}
|
||||
try:
|
||||
for tv in part_element.xpath("./*[local-name()='TemplateValue']"):
|
||||
tv_name = tv.get("Name")
|
||||
tv_type = tv.get("Type")
|
||||
if tv_name and tv_type:
|
||||
template_values[tv_name] = tv_type
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Error extrayendo TemplateValues Part UID={uid}: {e}")
|
||||
|
||||
negated_pins = {}
|
||||
try:
|
||||
for negated_elem in part_element.xpath("./*[local-name()='Negated']"):
|
||||
negated_pin_name = negated_elem.get("Name")
|
||||
if negated_pin_name:
|
||||
negated_pins[negated_pin_name] = True
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Error extrayendo Negated Pins Part UID={uid}: {e}")
|
||||
|
||||
version = part_element.get("Version")
|
||||
# Map XML names to internal types used by x2_process
|
||||
name_mapped = name_orig
|
||||
if name_orig == "Se":
|
||||
name_mapped = "TON_S5"
|
||||
elif name_orig == "Sd":
|
||||
name_mapped = "TONR_S5"
|
||||
elif name_orig == "PBox":
|
||||
name_mapped = "P_TRIG"
|
||||
elif name_orig == "NBox":
|
||||
name_mapped = "N_TRIG"
|
||||
elif name_orig == "RCoil":
|
||||
name_mapped = "R"
|
||||
elif name_orig == "SCoil":
|
||||
name_mapped = "S"
|
||||
elif name_orig == "SdCoil":
|
||||
name_mapped = "SR" # Map S5 Set-Dominant to SR internal type
|
||||
elif name_orig == "BLKMOV":
|
||||
name_mapped = "BLKMOV" # Keep as is
|
||||
# Add other mappings if necessary (e.g., RsCoil -> RS)
|
||||
|
||||
part_data = {
|
||||
"uid": uid,
|
||||
"type": name_mapped, # Use the mapped type
|
||||
"original_type": name_orig, # Store original name for reference if needed
|
||||
"template_values": template_values,
|
||||
"negated_pins": negated_pins,
|
||||
}
|
||||
if version:
|
||||
part_data["version"] = version
|
||||
|
||||
return part_data
|
||||
|
||||
|
||||
# parse_call - No changes needed from previous corrected version
|
||||
def parse_call(call_element):
|
||||
"""Parses Call elements (FC/FB calls)."""
|
||||
if call_element is None:
|
||||
return None
|
||||
uid = call_element.get("UId")
|
||||
if not uid:
|
||||
print(
|
||||
f"Error: Call encontrado sin UID: {etree.tostring(call_element, encoding='unicode')}"
|
||||
)
|
||||
return None
|
||||
|
||||
# Use local-name() for CallInfo
|
||||
call_info_elem = call_element.xpath("./*[local-name()='CallInfo']")
|
||||
if not call_info_elem:
|
||||
print(f"Error: Call UID {uid} sin elemento CallInfo.")
|
||||
return None
|
||||
call_info = call_info_elem[0]
|
||||
|
||||
block_name = call_info.get("Name")
|
||||
block_type = call_info.get("BlockType") # FC, FB
|
||||
|
||||
if not block_name or not block_type:
|
||||
print(f"Error: CallInfo para UID {uid} sin Name o BlockType.")
|
||||
return None
|
||||
|
||||
call_data = {
|
||||
"uid": uid,
|
||||
"type": "Call", # Generic type for our JSON
|
||||
"block_name": block_name,
|
||||
"block_type": block_type,
|
||||
"template_values": {}, # Add fields for consistency with parse_part
|
||||
"negated_pins": {},
|
||||
}
|
||||
|
||||
# Instance info for FBs
|
||||
instance_name = None
|
||||
if block_type == "FB":
|
||||
# Use local-name() for Instance and Symbol
|
||||
instance_elem = call_info.xpath("./*[local-name()='Instance']")
|
||||
if instance_elem:
|
||||
symbol_elem = instance_elem[0].xpath("./*[local-name()='Symbol']")
|
||||
if symbol_elem:
|
||||
instance_name = get_symbol_name(symbol_elem[0])
|
||||
if instance_name:
|
||||
call_data["instance_db"] = (
|
||||
instance_name # Store the formatted name directly
|
||||
)
|
||||
|
||||
return call_data
|
||||
|
||||
|
||||
# --- Function parse_network (Main logic per network) ---
|
||||
def parse_network(network_element):
|
||||
if network_element is None:
|
||||
return {
|
||||
"id": "ERROR",
|
||||
"title": "Invalid Network Element",
|
||||
"logic": [],
|
||||
"error": "Input element was None",
|
||||
}
|
||||
network_id = network_element.get("ID")
|
||||
|
||||
title_node = network_element.xpath(
|
||||
".//*[local-name()='MultilingualText'][@CompositionName='Title']"
|
||||
)
|
||||
network_title = (
|
||||
get_multilingual_text(title_node[0]) if title_node else f"Network {network_id}"
|
||||
)
|
||||
|
||||
comment_node = network_element.xpath(
|
||||
".//*[local-name()='MultilingualText'][@CompositionName='Comment']"
|
||||
)
|
||||
network_comment = get_multilingual_text(comment_node[0]) if comment_node else ""
|
||||
|
||||
flgnet_list = network_element.xpath(".//flg:FlgNet", namespaces=ns)
|
||||
if not flgnet_list:
|
||||
return {
|
||||
"id": network_id,
|
||||
"title": network_title,
|
||||
"comment": network_comment,
|
||||
"logic": [],
|
||||
"error": "FlgNet not found",
|
||||
}
|
||||
flgnet = flgnet_list[0]
|
||||
|
||||
# 1. Parse Access, Parts, and Calls
|
||||
access_map = {}
|
||||
for acc in flgnet.xpath(".//flg:Access", namespaces=ns):
|
||||
if acc_info := parse_access(acc):
|
||||
access_map[acc_info["uid"]] = acc_info
|
||||
|
||||
parts_and_calls_map = {}
|
||||
instruction_elements = flgnet.xpath(".//flg:Part | .//flg:Call", namespaces=ns)
|
||||
for element in instruction_elements:
|
||||
parsed_info = None
|
||||
if element.tag == etree.QName(ns["flg"], "Part"):
|
||||
parsed_info = parse_part(element)
|
||||
elif element.tag == etree.QName(ns["flg"], "Call"):
|
||||
parsed_info = parse_call(element)
|
||||
|
||||
if parsed_info and "uid" in parsed_info:
|
||||
parts_and_calls_map[parsed_info["uid"]] = parsed_info
|
||||
|
||||
# 2. Parse Wires
|
||||
wire_connections = defaultdict(list)
|
||||
source_connections = defaultdict(list)
|
||||
flg_ns_uri = ns["flg"]
|
||||
for wire in flgnet.xpath(".//flg:Wire", namespaces=ns):
|
||||
source_uid, source_pin, dest_uid, dest_pin = None, None, None, None
|
||||
source_elem = wire.xpath("./*[1]")[0]
|
||||
dest_elem = wire.xpath("./*[2]")[0]
|
||||
|
||||
if source_elem.tag == etree.QName(flg_ns_uri, "Powerrail"):
|
||||
source_uid, source_pin = "POWERRAIL", "out"
|
||||
elif source_elem.tag == etree.QName(flg_ns_uri, "IdentCon"):
|
||||
source_uid, source_pin = source_elem.get("UId"), "value"
|
||||
elif source_elem.tag == etree.QName(flg_ns_uri, "NameCon"):
|
||||
source_uid, source_pin = source_elem.get("UId"), source_elem.get("Name")
|
||||
|
||||
if dest_elem.tag == etree.QName(flg_ns_uri, "IdentCon"):
|
||||
dest_uid, dest_pin = dest_elem.get("UId"), "value"
|
||||
elif dest_elem.tag == etree.QName(flg_ns_uri, "NameCon"):
|
||||
dest_uid, dest_pin = dest_elem.get("UId"), dest_elem.get("Name")
|
||||
elif dest_elem.tag == etree.QName(flg_ns_uri, "OpenCon"):
|
||||
dest_uid, dest_pin = "OPEN", "in"
|
||||
|
||||
if dest_uid and dest_pin and source_uid is not None and source_pin is not None:
|
||||
if dest_uid != "OPEN":
|
||||
dest_key = (dest_uid, dest_pin)
|
||||
source_info = (source_uid, source_pin)
|
||||
if source_info not in wire_connections[dest_key]:
|
||||
wire_connections[dest_key].append(source_info)
|
||||
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)
|
||||
|
||||
# 3. Build Initial Logic Representation
|
||||
all_logic_steps = {}
|
||||
for instr_uid, instr_info in parts_and_calls_map.items():
|
||||
instruction_repr = {
|
||||
"instruction_uid": instr_uid,
|
||||
**instr_info,
|
||||
"inputs": {},
|
||||
"outputs": {},
|
||||
}
|
||||
|
||||
# *** ADD DSTBLK to possible inputs ***
|
||||
possible_input_pins = {
|
||||
"en",
|
||||
"in",
|
||||
"in1",
|
||||
"in2",
|
||||
"in3",
|
||||
"in4",
|
||||
"operand",
|
||||
"bit",
|
||||
"pre",
|
||||
"clk",
|
||||
"s",
|
||||
"tv",
|
||||
"r",
|
||||
"S",
|
||||
"R1",
|
||||
"SRCBLK",
|
||||
"DSTBLK",
|
||||
}
|
||||
|
||||
for dest_pin_name in possible_input_pins:
|
||||
dest_key = (instr_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 = {"out", "out1", "Q", "eno", "RET_VAL", "q", "et"}
|
||||
for src_pin_name in possible_output_pins:
|
||||
source_key = (instr_uid, src_pin_name)
|
||||
if source_key in source_connections:
|
||||
dest_access_list = []
|
||||
for dest_uid, dest_pin in source_connections[source_key]:
|
||||
if dest_uid in access_map:
|
||||
if access_map[dest_uid] not in dest_access_list:
|
||||
dest_access_list.append(access_map[dest_uid])
|
||||
if dest_access_list:
|
||||
instruction_repr["outputs"][src_pin_name] = dest_access_list
|
||||
|
||||
all_logic_steps[instr_uid] = instruction_repr
|
||||
|
||||
# 4. EN Connection Inference
|
||||
functional_block_types = {
|
||||
"Move",
|
||||
"Add",
|
||||
"Sub",
|
||||
"Mul",
|
||||
"Div",
|
||||
"Mod",
|
||||
"Convert",
|
||||
"Call",
|
||||
"BLKMOV",
|
||||
}
|
||||
# Use MAPPED types for RLO generators
|
||||
rlo_generators = {
|
||||
"Contact",
|
||||
"O",
|
||||
"Eq",
|
||||
"Ne",
|
||||
"Gt",
|
||||
"Lt",
|
||||
"Ge",
|
||||
"Le",
|
||||
"And",
|
||||
"Xor",
|
||||
"P_TRIG",
|
||||
"N_TRIG",
|
||||
}
|
||||
|
||||
try:
|
||||
sorted_uids = sorted(all_logic_steps.keys(), key=lambda x: int(x))
|
||||
except ValueError:
|
||||
sorted_uids = sorted(all_logic_steps.keys())
|
||||
|
||||
processed_for_en_inference = set()
|
||||
current_logic_list_for_en = [all_logic_steps[uid] for uid in sorted_uids]
|
||||
|
||||
for i, instruction in enumerate(current_logic_list_for_en):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"] # Use the mapped type
|
||||
|
||||
if (
|
||||
instr_type in functional_block_types
|
||||
and "en" not in instruction["inputs"]
|
||||
and instr_uid not in processed_for_en_inference
|
||||
):
|
||||
inferred_en_source = None
|
||||
if i > 0:
|
||||
# Simple lookback to previous instruction
|
||||
prev_instr = current_logic_list_for_en[i - 1]
|
||||
prev_uid = prev_instr["instruction_uid"]
|
||||
prev_type = prev_instr["type"]
|
||||
# Check if previous instruction has a mappable 'out' or 'eno'
|
||||
# We check source_connections map for actual wire existence
|
||||
prev_has_out_wire = any(
|
||||
dest[0] != "OPEN"
|
||||
for dest in source_connections.get((prev_uid, "out"), [])
|
||||
)
|
||||
prev_has_eno_wire = any(
|
||||
dest[0] != "OPEN"
|
||||
for dest in source_connections.get((prev_uid, "eno"), [])
|
||||
)
|
||||
|
||||
if prev_type in rlo_generators and prev_has_out_wire:
|
||||
inferred_en_source = {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": prev_uid,
|
||||
"source_instruction_type": prev_type,
|
||||
"source_pin": "out",
|
||||
}
|
||||
elif prev_type in functional_block_types and prev_has_eno_wire:
|
||||
inferred_en_source = {
|
||||
"type": "connection",
|
||||
"source_instruction_uid": prev_uid,
|
||||
"source_instruction_type": prev_type,
|
||||
"source_pin": "eno",
|
||||
}
|
||||
|
||||
if inferred_en_source:
|
||||
all_logic_steps[instr_uid]["inputs"]["en"] = inferred_en_source
|
||||
processed_for_en_inference.add(instr_uid)
|
||||
|
||||
# 5. Final Logic Ordering
|
||||
network_logic = [all_logic_steps[uid] for uid in sorted_uids]
|
||||
|
||||
return {
|
||||
"id": network_id,
|
||||
"title": network_title,
|
||||
"comment": network_comment,
|
||||
"logic": network_logic,
|
||||
}
|
||||
|
||||
|
||||
# --- Main XML to JSON Conversion Function ---
|
||||
# convert_xml_to_json - No significant changes needed from previous version
|
||||
def convert_xml_to_json(xml_filepath, json_filepath):
|
||||
print(f"Iniciando conversión de '{xml_filepath}' a '{json_filepath}'...")
|
||||
if not os.path.exists(xml_filepath):
|
||||
print(f"Error Crítico: Archivo XML no encontrado: '{xml_filepath}'")
|
||||
return
|
||||
try:
|
||||
print("Paso 1: Parseando archivo XML...")
|
||||
# Disable DTD loading for security and compatibility
|
||||
parser = etree.XMLParser(
|
||||
remove_blank_text=True, load_dtd=False, resolve_entities=False
|
||||
)
|
||||
tree = etree.parse(xml_filepath, parser)
|
||||
root = tree.getroot()
|
||||
print("Paso 1: Parseo XML completado.")
|
||||
|
||||
# Detect block type (FC or FB) - Look for SW.Blocks.FC or SW.Blocks.FB
|
||||
block_node = None
|
||||
block_xpath = ".//*[local-name()='SW.Blocks.FC' or local-name()='SW.Blocks.FB']"
|
||||
block_list = root.xpath(block_xpath)
|
||||
|
||||
if not block_list:
|
||||
print("Error Crítico: No se encontró <SW.Blocks.FC> o <SW.Blocks.FB>.")
|
||||
return
|
||||
block_node = block_list[0]
|
||||
block_tag_name = etree.QName(
|
||||
block_node.tag
|
||||
).localname # SW.Blocks.FC or SW.Blocks.FB
|
||||
print(
|
||||
f"Paso 2: Bloque {block_tag_name} encontrado (ID={block_node.get('ID')})."
|
||||
)
|
||||
|
||||
print("Paso 3: Extrayendo atributos del bloque...")
|
||||
attribute_list_node = block_node.xpath("./*[local-name()='AttributeList']")
|
||||
block_name_val, block_number_val, block_lang_val = "Unknown", None, "Unknown"
|
||||
if attribute_list_node:
|
||||
attr_list = attribute_list_node[0]
|
||||
name_node = attr_list.xpath("./*[local-name()='Name']/text()")
|
||||
block_name_val = name_node[0].strip() if name_node else block_name_val
|
||||
num_node = attr_list.xpath("./*[local-name()='Number']/text()")
|
||||
try:
|
||||
block_number_val = int(num_node[0]) if num_node else None
|
||||
except ValueError:
|
||||
block_number_val = None # Handle non-integer Number
|
||||
lang_node = attr_list.xpath(
|
||||
"./*[local-name()='ProgrammingLanguage']/text()"
|
||||
)
|
||||
block_lang_val = lang_node[0].strip() if lang_node else block_lang_val
|
||||
print(
|
||||
f"Paso 3: Atributos: Nombre='{block_name_val}', Número={block_number_val}, Lenguaje='{block_lang_val}'"
|
||||
)
|
||||
else:
|
||||
print("Advertencia: No se encontró AttributeList para el bloque.")
|
||||
|
||||
# Get block comment
|
||||
block_comment_val = ""
|
||||
comment_node_list = block_node.xpath(
|
||||
"./*[local-name()='ObjectList']/*[local-name()='MultilingualText'][@CompositionName='Comment']"
|
||||
)
|
||||
if comment_node_list:
|
||||
block_comment_val = get_multilingual_text(comment_node_list[0])
|
||||
|
||||
# Initialize result dictionary
|
||||
result = {
|
||||
"block_name": block_name_val,
|
||||
"block_number": block_number_val,
|
||||
"language": block_lang_val,
|
||||
"block_comment": block_comment_val,
|
||||
"interface": {},
|
||||
"networks": [],
|
||||
}
|
||||
|
||||
print("Paso 4: Extrayendo la interfaz del bloque...")
|
||||
if attribute_list_node:
|
||||
interface_node = attribute_list_node[0].xpath(
|
||||
"./*[local-name()='Interface']"
|
||||
)
|
||||
if interface_node:
|
||||
print("Paso 4: Nodo Interface encontrado.")
|
||||
# Iterate through sections using the correct namespace prefix 'iface'
|
||||
for section in interface_node[0].xpath(
|
||||
".//iface:Section", namespaces=ns
|
||||
):
|
||||
section_name = section.get(
|
||||
"Name"
|
||||
) # Input, Output, InOut, Temp, Constant, Return
|
||||
members = []
|
||||
for member in section.xpath("./iface:Member", namespaces=ns):
|
||||
member_name = member.get("Name")
|
||||
member_dtype = member.get("Datatype")
|
||||
if member_name and member_dtype:
|
||||
member_info = {
|
||||
"name": member_name,
|
||||
"datatype": member_dtype,
|
||||
}
|
||||
members.append(member_info)
|
||||
if members:
|
||||
result["interface"][section_name] = members
|
||||
if not result["interface"]:
|
||||
print("Advertencia: Interface sin secciones iface:Section válidas.")
|
||||
else:
|
||||
print(
|
||||
"Advertencia: No se encontró <Interface> DENTRO de <AttributeList>."
|
||||
)
|
||||
if not result["interface"]:
|
||||
print("Advertencia: No se pudo extraer información de la interfaz.")
|
||||
|
||||
print("Paso 5: Extrayendo y PROCESANDO lógica de redes (CompileUnits)...")
|
||||
networks_processed_count = 0
|
||||
object_list_node = block_node.xpath("./*[local-name()='ObjectList']")
|
||||
if object_list_node:
|
||||
compile_units = object_list_node[0].xpath(
|
||||
"./*[local-name()='SW.Blocks.CompileUnit']"
|
||||
)
|
||||
print(
|
||||
f"Paso 5: Se encontraron {len(compile_units)} elementos SW.Blocks.CompileUnit."
|
||||
)
|
||||
for network_elem in compile_units:
|
||||
networks_processed_count += 1
|
||||
parsed_network = parse_network(network_elem)
|
||||
if parsed_network and parsed_network.get("error") is None:
|
||||
result["networks"].append(parsed_network)
|
||||
elif parsed_network:
|
||||
print(
|
||||
f"Error: Falló parseo red ID={parsed_network.get('id')}: {parsed_network.get('error')}"
|
||||
)
|
||||
result["networks"].append(
|
||||
parsed_network
|
||||
) # Include network with error marker
|
||||
else:
|
||||
print(
|
||||
f"Error Crítico: parse_network devolvió None para CompileUnit (ID={network_elem.get('ID')})."
|
||||
)
|
||||
|
||||
if networks_processed_count == 0:
|
||||
print("Advertencia: ObjectList sin SW.Blocks.CompileUnit.")
|
||||
else:
|
||||
print("Advertencia: No se encontró ObjectList.")
|
||||
|
||||
print("Paso 6: Escribiendo el resultado en el archivo JSON...")
|
||||
if not result["interface"]:
|
||||
print("ADVERTENCIA FINAL: 'interface' está vacía.")
|
||||
if not result["networks"]:
|
||||
print("ADVERTENCIA FINAL: 'networks' está vacía.")
|
||||
|
||||
try:
|
||||
with open(json_filepath, "w", encoding="utf-8") as f:
|
||||
json.dump(
|
||||
result, f, indent=4, ensure_ascii=False
|
||||
) # ensure_ascii=False is important
|
||||
print(f"Paso 6: Escritura completada.")
|
||||
print(f"Conversión finalizada. JSON guardado en: '{json_filepath}'")
|
||||
except IOError as e:
|
||||
print(
|
||||
f"Error Crítico: No se pudo escribir JSON en '{json_filepath}'. Error: {e}"
|
||||
)
|
||||
except TypeError as e:
|
||||
print(f"Error Crítico: Problema al serializar a JSON. Error: {e}")
|
||||
|
||||
except etree.XMLSyntaxError as e:
|
||||
print(f"Error Crítico: Sintaxis XML en '{xml_filepath}'. Detalles: {e}")
|
||||
except Exception as e:
|
||||
print(f"Error Crítico: Error inesperado durante la conversión: {e}")
|
||||
print("--- Traceback ---")
|
||||
traceback.print_exc()
|
||||
print("--- Fin Traceback ---")
|
||||
|
||||
|
||||
# --- Punto de Entrada Principal ---
|
||||
if __name__ == "__main__":
|
||||
xml_file = "BlenderCtrl__Main.xml"
|
||||
json_file = xml_file.replace(".xml", "_simplified.json")
|
||||
convert_xml_to_json(xml_file, json_file)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,218 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
# --- Helper Functions ---
|
||||
# Use the CORRECT version from x2_process.py
|
||||
def format_variable_name(name):
|
||||
"""Formats variable names for SCL, preserving quotes for structured names."""
|
||||
if not name:
|
||||
return "_INVALID_NAME_"
|
||||
if name.startswith('"') and name.endswith('"'):
|
||||
return name
|
||||
prefix = ""
|
||||
if name.startswith("#"):
|
||||
prefix = "#"
|
||||
name = name[1:]
|
||||
if not name:
|
||||
return "_INVALID_NAME_"
|
||||
if not re.match(r"^[a-zA-Z_]", name[0]):
|
||||
name = "_" + name
|
||||
name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
|
||||
return prefix + name
|
||||
|
||||
|
||||
def generate_scl(processed_json_filepath, output_scl_filepath):
|
||||
"""Genera un archivo SCL a partir del JSON procesado."""
|
||||
if not os.path.exists(processed_json_filepath):
|
||||
print(
|
||||
f"Error: Archivo JSON procesado no encontrado en '{processed_json_filepath}'"
|
||||
)
|
||||
return
|
||||
print(f"Cargando JSON procesado desde: {processed_json_filepath}")
|
||||
try:
|
||||
with open(processed_json_filepath, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Error al cargar JSON: {e}")
|
||||
return
|
||||
|
||||
# --- Block Info ---
|
||||
block_name_orig = data.get("block_name", "UnknownBlock")
|
||||
block_number = data.get("block_number")
|
||||
block_lang = data.get("language", "LAD")
|
||||
block_comment = data.get("block_comment", "")
|
||||
|
||||
# --- Variable Detection ---
|
||||
temp_vars_base = set() # Base names like _temp_...
|
||||
stat_vars = {} # Quoted Name -> TYPE (Bool, TON, TONR)
|
||||
|
||||
temp_pattern = re.compile(r"#(_temp_[a-zA-Z0-9_]+)") # Capture base name after #
|
||||
# Regex needs to capture the QUOTED name from SCL
|
||||
stat_pattern_bool = re.compile(
|
||||
r'("stat_(?:ptrig|ntrig|sr)_mem_[a-zA-Z0-9_]+")'
|
||||
) # Edge/SR mem bits
|
||||
stat_pattern_ton = re.compile(r'("stat_TON_[a-zA-Z0-9_]+")') # TON instances
|
||||
stat_pattern_tonr = re.compile(r'("stat_TONR_[a-zA-Z0-9_]+")') # TONR instances
|
||||
|
||||
for network in data.get("networks", []):
|
||||
for instruction in network.get("logic", []):
|
||||
scl_code = instruction.get("scl", "")
|
||||
if scl_code:
|
||||
temp_vars_base.update(temp_pattern.findall(scl_code))
|
||||
for name in stat_pattern_bool.findall(scl_code):
|
||||
stat_vars[name] = "Bool"
|
||||
for name in stat_pattern_ton.findall(scl_code):
|
||||
stat_vars[name] = "TON"
|
||||
for name in stat_pattern_tonr.findall(scl_code):
|
||||
stat_vars[name] = "TONR"
|
||||
|
||||
has_stat = bool(stat_vars)
|
||||
interface_temps_list = data.get("interface", {}).get("Temp", [])
|
||||
has_temp = bool(temp_vars_base or interface_temps_list)
|
||||
block_type_keyword = "FUNCTION_BLOCK" if has_stat or has_temp else "FUNCTION"
|
||||
scl_block_name = format_variable_name(block_name_orig) # Format name correctly
|
||||
|
||||
print(f"Generando SCL para bloque: {scl_block_name} como {block_type_keyword}")
|
||||
print(f"Variables temporales (#_temp_...) detectadas: {len(temp_vars_base)}")
|
||||
print(f"Variables estáticas (stat_...) detectadas: {len(stat_vars)}")
|
||||
|
||||
# --- Build SCL Output ---
|
||||
scl_output = []
|
||||
scl_output.append(f"// Block Name (Original): {block_name_orig}")
|
||||
if block_number:
|
||||
scl_output.append(f"// Block Number: {block_number}")
|
||||
scl_output.append(f"// Original Language: {block_lang}")
|
||||
if block_comment:
|
||||
scl_output.append(f"// Block Comment: {block_comment}")
|
||||
scl_output.append("")
|
||||
scl_output.append(f"{block_type_keyword} {scl_block_name}")
|
||||
scl_output.append("{ S7_Optimized_Access := 'TRUE' }")
|
||||
scl_output.append("VERSION : 0.1")
|
||||
scl_output.append("")
|
||||
|
||||
# --- VAR Sections ---
|
||||
def add_var_section(section_name, members_list):
|
||||
if not members_list:
|
||||
return
|
||||
scl_output.append(f"VAR_{section_name}")
|
||||
for member in members_list:
|
||||
scl_name = format_variable_name(
|
||||
member["name"]
|
||||
) # Format interface var names
|
||||
scl_output.append(f" {scl_name} : {member['datatype']};")
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
interface_data = data.get("interface", {})
|
||||
add_var_section("INPUT", interface_data.get("Input", []))
|
||||
add_var_section("OUTPUT", interface_data.get("Output", []))
|
||||
add_var_section("IN_OUT", interface_data.get("InOut", []))
|
||||
|
||||
if stat_vars:
|
||||
scl_output.append("VAR_STAT")
|
||||
for var_name_quoted in sorted(stat_vars.keys()):
|
||||
var_type = stat_vars[var_name_quoted]
|
||||
comment = (
|
||||
f"// Instance for {var_type}"
|
||||
if var_type in ["TON", "TONR"]
|
||||
else "// Memory Bit"
|
||||
)
|
||||
scl_output.append(f" {var_name_quoted} : {var_type}; {comment}")
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
declared_temps_formatted = set()
|
||||
temp_declarations = []
|
||||
if interface_temps_list:
|
||||
for var in interface_temps_list:
|
||||
scl_name = format_variable_name(var["name"])
|
||||
temp_declarations.append(
|
||||
f" {scl_name} : {var['datatype']}; // From Interface"
|
||||
)
|
||||
declared_temps_formatted.add(scl_name)
|
||||
if temp_vars_base:
|
||||
for base_name in sorted(list(temp_vars_base)):
|
||||
# Declare using the base name, quoted
|
||||
scl_name_declare = format_variable_name(f'"{base_name}"')
|
||||
if scl_name_declare not in declared_temps_formatted:
|
||||
# Simple inference based on common pin names in the base name
|
||||
inferred_type = "Bool" # Default
|
||||
if "ret_val" in base_name:
|
||||
inferred_type = "Int"
|
||||
elif "_et" in base_name:
|
||||
inferred_type = "Time"
|
||||
temp_declarations.append(
|
||||
f" {scl_name_declare} : {inferred_type}; // Auto-generated temporary"
|
||||
)
|
||||
declared_temps_formatted.add(scl_name_declare)
|
||||
if temp_declarations:
|
||||
scl_output.append("VAR_TEMP")
|
||||
scl_output.extend(temp_declarations)
|
||||
scl_output.append("END_VAR")
|
||||
scl_output.append("")
|
||||
|
||||
# --- Block Body ---
|
||||
scl_output.append("BEGIN")
|
||||
scl_output.append("")
|
||||
for i, network in enumerate(data.get("networks", [])):
|
||||
network_title = network.get("title", f'Network {network.get("id")}')
|
||||
network_comment = network.get("comment", "")
|
||||
scl_output.append(f" // Network {i+1}: {network_title}")
|
||||
if network_comment:
|
||||
for line in network_comment.splitlines():
|
||||
scl_output.append(f" // {line}")
|
||||
scl_output.append("")
|
||||
network_has_code = False
|
||||
for instruction in network.get("logic", []):
|
||||
if instruction.get("grouped", False):
|
||||
continue
|
||||
scl_code = instruction.get("scl")
|
||||
if scl_code:
|
||||
lines_to_add = []
|
||||
for line in scl_code.splitlines():
|
||||
line_strip = line.strip()
|
||||
is_simple_info_comment = line_strip.startswith(
|
||||
("// RLO:", "// Comparison Eq", "// Logic O")
|
||||
)
|
||||
# Keep essential comments (Errors, Grouping, Memory Updates) and actual SCL
|
||||
if (
|
||||
not is_simple_info_comment
|
||||
or line_strip.startswith("// ERROR")
|
||||
or line_strip.startswith(GROUPED_COMMENT)
|
||||
or "Edge Memory Update" in line_strip
|
||||
):
|
||||
lines_to_add.append(line)
|
||||
if lines_to_add:
|
||||
network_has_code = True
|
||||
for line in lines_to_add:
|
||||
scl_output.append(f" {line}")
|
||||
if network_has_code:
|
||||
scl_output.append("")
|
||||
|
||||
end_keyword = (
|
||||
"END_FUNCTION_BLOCK"
|
||||
if block_type_keyword == "FUNCTION_BLOCK"
|
||||
else "END_FUNCTION"
|
||||
)
|
||||
scl_output.append(end_keyword)
|
||||
|
||||
# --- Write File ---
|
||||
print(f"Escribiendo archivo SCL en: {output_scl_filepath}")
|
||||
try:
|
||||
with open(output_scl_filepath, "w", encoding="utf-8") as f:
|
||||
for line in scl_output:
|
||||
f.write(line + "\n")
|
||||
print("Generación de SCL completada.")
|
||||
except Exception as e:
|
||||
print(f"Error al escribir el archivo SCL: {e}")
|
||||
|
||||
|
||||
# --- Ejecución ---
|
||||
if __name__ == "__main__":
|
||||
xml_filename_base = "BlenderCtrl__Main"
|
||||
input_json_file = f"{xml_filename_base}_simplified_processed.json"
|
||||
output_scl_file = input_json_file.replace("_simplified_processed.json", ".scl")
|
||||
generate_scl(input_json_file, output_scl_file)
|
898
x1_to_json.py
898
x1_to_json.py
File diff suppressed because it is too large
Load Diff
580
x2_process.py
580
x2_process.py
|
@ -258,6 +258,134 @@ 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"]
|
||||
|
@ -315,52 +443,6 @@ def process_eq(instruction, network_id, scl_map, access_map):
|
|||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
|
||||
def process_coil(instruction, network_id, scl_map, access_map):
|
||||
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 # Dependencias no listas
|
||||
|
||||
# Validar y formatear operando
|
||||
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 # Marcar como procesado (con error)
|
||||
|
||||
operand_scl_formatted = format_variable_name(operand_scl)
|
||||
|
||||
# Simplificar RLO si es posible
|
||||
if in_rlo_scl == "(TRUE)":
|
||||
in_rlo_scl = "TRUE"
|
||||
elif in_rlo_scl == "(FALSE)":
|
||||
in_rlo_scl = "FALSE"
|
||||
|
||||
# Generar la asignación SCL
|
||||
scl_final = f"{operand_scl_formatted} := {in_rlo_scl};"
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Las bobinas no suelen tener salida ENO explícita en este contexto,
|
||||
# pero podríamos propagar el RLO de entrada si fuera necesario para alguna lógica posterior.
|
||||
# map_key_eno = (network_id, instr_uid, "eno")
|
||||
# scl_map[map_key_eno] = in_rlo_scl
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def process_convert(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
|
@ -424,7 +506,6 @@ def process_convert(instruction, network_id, scl_map, access_map):
|
|||
scl_map[map_key_eno] = en_scl # ENO sigue a EN
|
||||
return True
|
||||
|
||||
|
||||
def process_mod(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
|
@ -483,7 +564,6 @@ def process_mod(instruction, network_id, scl_map, access_map):
|
|||
scl_map[map_key_eno] = en_scl
|
||||
return True
|
||||
|
||||
|
||||
def process_add(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
|
@ -542,7 +622,6 @@ def process_add(instruction, network_id, scl_map, access_map):
|
|||
scl_map[map_key_eno] = en_scl
|
||||
return True
|
||||
|
||||
|
||||
def process_move(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
|
@ -608,225 +687,186 @@ def process_move(instruction, network_id, scl_map, access_map):
|
|||
return True
|
||||
|
||||
|
||||
def process_pbox(instruction, network_id, scl_map, access_map, network_logic_list):
|
||||
# --- FUNCIÓN UNIFICADA CORREGIDA para PBox y NBox ---
|
||||
|
||||
"""Genera SCL para PBox (P_TRIG) o NBox (N_TRIG)."""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type_original = instruction["type"] # PBox o NBox
|
||||
# print(f"DEBUG Edge: Intentando procesar {instr_type_original} UID {instr_uid} en Red {network_id}") # Debug
|
||||
|
||||
if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
|
||||
return False # Ya procesado o error
|
||||
|
||||
# 1. Obtener representaciones SCL de las entradas CLK y MemBit
|
||||
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 si las dependencias están listas
|
||||
if clk_scl is None:
|
||||
# print(f"DEBUG Edge: CLK no resuelto para {instr_type_original} UID {instr_uid}. Esperando.")
|
||||
return False # Dependencia CLK no lista
|
||||
if mem_bit_scl_original is None:
|
||||
# Esto es menos probable, pero por seguridad
|
||||
print(f"Error: No se pudo resolver MemBit para {instr_type_original} UID {instr_uid}.")
|
||||
instruction["scl"] = f"// ERROR: {instr_type_original} {instr_uid} MemBit no resuelto."
|
||||
instruction["type"] = instr_type_original + "_error"
|
||||
return True # Marcar como error
|
||||
|
||||
# 3. 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
|
||||
|
||||
# 4. Renombrar bit de memoria para VAR_STAT y formatear CLK
|
||||
mem_bit_name_clean = mem_bit_scl_original.strip('"')
|
||||
stat_mem_bit_scl = f'"stat_{mem_bit_name_clean}"' if not mem_bit_name_clean.startswith("stat_") else mem_bit_scl_original
|
||||
|
||||
clk_scl_formatted = clk_scl
|
||||
# Añadir paréntesis si es necesario (expresión compleja) - No a TRUE/FALSE
|
||||
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})"
|
||||
|
||||
# 5. Generar Lógica SCL específica para PBox o NBox
|
||||
result_pulse_scl = "FALSE" # SCL para la salida del flanco (pin 'out')
|
||||
scl_comment = ""
|
||||
|
||||
if instr_type_original == "PBox": # Flanco Positivo (P_TRIG)
|
||||
# Pulso = CLK actual Y NO Memoria anterior
|
||||
result_pulse_scl = f"{clk_scl_formatted} AND NOT {stat_mem_bit_scl}"
|
||||
scl_comment = f"// P_TRIG({clk_scl_formatted})"
|
||||
elif instr_type_original == "NBox": # Flanco Negativo (N_TRIG)
|
||||
# Pulso = NO CLK actual Y Memoria anterior
|
||||
result_pulse_scl = f"NOT {clk_scl_formatted} AND {stat_mem_bit_scl}"
|
||||
scl_comment = f"// N_TRIG({clk_scl_formatted})"
|
||||
else:
|
||||
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
|
||||
|
||||
# 6. Generar la actualización del bit de memoria (siempre se actualiza con el estado actual de CLK)
|
||||
scl_mem_update = f"{stat_mem_bit_scl} := {clk_scl_formatted};"
|
||||
|
||||
# 7. Almacenar Resultados
|
||||
# - El *pulso* resultante se almacena en el mapa para la salida 'out'.
|
||||
# - La *actualización de memoria* se almacena en el campo 'scl' de la instrucción.
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = result_pulse_scl
|
||||
# print(f"DEBUG Edge: {instr_type_original} UID {instr_uid} -> map['out'] = {result_pulse_scl}") # Debug
|
||||
|
||||
instruction["scl"] = f"{scl_mem_update} {scl_comment}" # Incluye la acción principal y un comentario
|
||||
instruction["type"] = instr_type_original + SCL_SUFFIX
|
||||
# print(f"DEBUG Edge: {instr_type_original} UID {instr_uid} -> instruction['scl'] = {instruction['scl']}") # Debug
|
||||
|
||||
# 8. Propagar ENO (generalmente sigue al CLK)
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = clk_scl # Usar el clk_scl original sin formato extra
|
||||
|
||||
# print(f"DEBUG Edge: {instr_type_original} UID {instr_uid} procesado exitosamente.") # Debug
|
||||
return True # Indicar que se procesó
|
||||
|
||||
# EN x2_process.py
|
||||
|
||||
def process_blkmov(instruction, network_id, scl_map, access_map):
|
||||
"""
|
||||
Genera SCL usando BLKMOV directamente como nombre de función,
|
||||
sin COUNT y con formato específico, según solicitud del usuario.
|
||||
ADVERTENCIA: Es MUY PROBABLE que esto NO compile en TIA Portal estándar,
|
||||
ya que BLKMOV no es una función SCL y MOVE_BLK requiere COUNT.
|
||||
"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
return False # Ya procesado o con error
|
||||
|
||||
mem_bit_input = instruction["inputs"].get("bit")
|
||||
mem_bit_scl = get_scl_representation(mem_bit_input, network_id, scl_map, access_map)
|
||||
# --- Obtener Entradas ---
|
||||
en_input = instruction["inputs"].get("en")
|
||||
en_scl = (
|
||||
get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
if en_input
|
||||
else "TRUE"
|
||||
)
|
||||
srcblk_info = instruction["inputs"].get("SRCBLK")
|
||||
# ¡IMPORTANTE! Obtenemos el nombre RAW antes de formatearlo para usarlo como pide el usuario
|
||||
raw_srcblk_name = srcblk_info.get("name") if srcblk_info else None
|
||||
|
||||
if mem_bit_scl is None:
|
||||
return False # Dependencia no lista
|
||||
# Verificar dependencias de entrada (solo necesitamos que EN esté resuelto)
|
||||
if en_scl is None:
|
||||
return False # Dependencia EN no lista
|
||||
if raw_srcblk_name is None:
|
||||
print(f"Error: BLKMOV {instr_uid} sin información válida para SRCBLK.")
|
||||
instruction["scl"] = f"// ERROR: BLKMOV {instr_uid} sin SRCBLK válido."
|
||||
instruction["type"] += "_error"
|
||||
return True
|
||||
|
||||
# Validar y formatear el bit de memoria
|
||||
if not (mem_bit_input and mem_bit_input.get("type") == "variable"):
|
||||
print(f"Error: PBOX {instr_uid} 'bit' no es variable o falta información.")
|
||||
instruction["scl"] = (
|
||||
f"// ERROR: PBox {instr_uid} 'bit' no es variable o falta info"
|
||||
)
|
||||
# --- Obtener Destinos (Salidas) ---
|
||||
# RET_VAL (Usamos get_target_scl_name para manejar variables temporales si es necesario)
|
||||
retval_target_scl = get_target_scl_name(
|
||||
instruction, "RET_VAL", network_id, default_to_temp=True
|
||||
)
|
||||
if retval_target_scl is None:
|
||||
print(f"Error: BLKMOV {instr_uid} sin destino claro para RET_VAL.")
|
||||
instruction["scl"] = f"// ERROR: BLKMOV {instr_uid} sin destino RET_VAL"
|
||||
instruction["type"] += "_error"
|
||||
return True # Procesado con error
|
||||
return True
|
||||
|
||||
mem_bit_scl_formatted = format_variable_name(mem_bit_scl)
|
||||
|
||||
# --- Lógica para inferir CLK (similar a la versión anterior) ---
|
||||
# Determinar si es P_TRIG (conectado a una bobina)
|
||||
is_likely_p_trig = False
|
||||
consuming_coil_uid = None
|
||||
for potential_consumer in network_logic_list:
|
||||
coil_input_signal = potential_consumer.get("inputs", {}).get("in")
|
||||
if (
|
||||
isinstance(coil_input_signal, dict)
|
||||
and coil_input_signal.get("type") == "connection"
|
||||
and coil_input_signal.get("source_instruction_uid") == instr_uid
|
||||
and coil_input_signal.get("source_pin")
|
||||
== "out" # PBox output alimenta la bobina
|
||||
):
|
||||
consumer_type_original = (
|
||||
potential_consumer.get("type", "")
|
||||
.replace("_scl", "")
|
||||
.replace("_error", "")
|
||||
)
|
||||
if consumer_type_original == "Coil":
|
||||
is_likely_p_trig = True
|
||||
consuming_coil_uid = potential_consumer.get("instruction_uid")
|
||||
break # Encontrado consumidor de bobina
|
||||
|
||||
rlo_scl = None # Este será el CLK inferido
|
||||
if is_likely_p_trig:
|
||||
# Buscar hacia atrás la fuente del RLO que alimenta este PBox
|
||||
clk_source_found = False
|
||||
current_instr_index = -1
|
||||
for i, instr in enumerate(network_logic_list):
|
||||
if instr["instruction_uid"] == instr_uid:
|
||||
current_instr_index = i
|
||||
break
|
||||
|
||||
if current_instr_index != -1:
|
||||
# Buscar la entrada 'in' del PBox si existe explícitamente
|
||||
pbox_in_signal = instruction.get("inputs", {}).get("in")
|
||||
if pbox_in_signal:
|
||||
rlo_scl = get_scl_representation(
|
||||
pbox_in_signal, network_id, scl_map, access_map
|
||||
)
|
||||
if rlo_scl is not None:
|
||||
clk_source_found = True
|
||||
# print(f"DEBUG: PBox {instr_uid} CLK encontrado por pin 'in': {rlo_scl}")
|
||||
|
||||
# Si no hay pin 'in' explícito, buscar hacia atrás (lógica LAD clásica)
|
||||
if not clk_source_found:
|
||||
# print(f"DEBUG: PBox {instr_uid} buscando CLK hacia atrás...")
|
||||
for i in range(current_instr_index - 1, -1, -1):
|
||||
prev_instr = network_logic_list[i]
|
||||
prev_instr_uid = prev_instr["instruction_uid"]
|
||||
prev_instr_type_original = (
|
||||
prev_instr.get("type", "")
|
||||
.replace(SCL_SUFFIX, "")
|
||||
.replace("_error", "")
|
||||
)
|
||||
|
||||
# ¿Es una instrucción que genera RLO booleano?
|
||||
if prev_instr_type_original in [
|
||||
"Contact",
|
||||
"Eq",
|
||||
"O",
|
||||
"PBox",
|
||||
"And",
|
||||
"Xor",
|
||||
"Ne",
|
||||
"Gt",
|
||||
"Lt",
|
||||
"Ge",
|
||||
"Le",
|
||||
]:
|
||||
map_key_prev_out = (network_id, prev_instr_uid, "out")
|
||||
potential_clk_scl = scl_map.get(map_key_prev_out)
|
||||
if potential_clk_scl is not None:
|
||||
rlo_scl = potential_clk_scl
|
||||
clk_source_found = True
|
||||
# print(f"DEBUG: PBox {instr_uid} CLK encontrado de {prev_instr_type_original} {prev_instr_uid} (out): {rlo_scl}")
|
||||
break
|
||||
# ¿Es un bloque funcional cuya salida ENO podría ser el RLO?
|
||||
elif prev_instr_type_original in [
|
||||
"Move",
|
||||
"Add",
|
||||
"Convert",
|
||||
"Mod",
|
||||
"Call",
|
||||
]: # Añadir otros bloques funcionales
|
||||
map_key_prev_eno = (network_id, prev_instr_uid, "eno")
|
||||
potential_clk_scl = scl_map.get(map_key_prev_eno)
|
||||
if potential_clk_scl is not None:
|
||||
rlo_scl = potential_clk_scl
|
||||
clk_source_found = True
|
||||
# print(f"DEBUG: PBox {instr_uid} CLK encontrado de {prev_instr_type_original} {prev_instr_uid} (eno): {rlo_scl}")
|
||||
break
|
||||
# Si encontramos una bobina, el RLO se detiene ahí
|
||||
elif prev_instr_type_original == "Coil":
|
||||
# print(f"DEBUG: PBox {instr_uid} búsqueda CLK detenida por Coil {prev_instr_uid}")
|
||||
break
|
||||
|
||||
if not clk_source_found:
|
||||
print(f"Error: No se pudo inferir CLK para P_TRIG PBOX {instr_uid}")
|
||||
instruction["scl"] = f"// ERROR: PBox {instr_uid} (P_TRIG) sin CLK inferido"
|
||||
instruction["type"] += "_error"
|
||||
return True # Procesado con error
|
||||
|
||||
if rlo_scl is None:
|
||||
# print(f"DEBUG: PBox {instr_uid} CLK encontrado pero valor es None, esperando...")
|
||||
return False # Dependencia (CLK) no resuelta aún
|
||||
|
||||
# --- Generar SCL ---
|
||||
scl_comment = ""
|
||||
result_scl = "" # El valor que PBox pone en scl_map['out']
|
||||
|
||||
if is_likely_p_trig:
|
||||
# Formatear CLK si es variable (poco probable, suele ser resultado lógico)
|
||||
# clk_signal_formatted = format_variable_name(rlo_scl) if ... else rlo_scl
|
||||
clk_signal_formatted = (
|
||||
rlo_scl # Asumir que ya está bien formateado o es una expresión
|
||||
)
|
||||
|
||||
# Añadir paréntesis si CLK es complejo
|
||||
if (
|
||||
" " in clk_signal_formatted
|
||||
or "AND" in clk_signal_formatted
|
||||
or "OR" in clk_signal_formatted
|
||||
) and not (
|
||||
clk_signal_formatted.startswith("(") and clk_signal_formatted.endswith(")")
|
||||
):
|
||||
clk_signal_formatted = f"({clk_signal_formatted})"
|
||||
|
||||
# Generar llamada a función de flanco (asumimos P_TRIG)
|
||||
# Necesitamos un nombre para la instancia del flanco, usualmente una variable STAT
|
||||
# Podríamos generarla automáticamente o requerirla en el XML.
|
||||
# Generación automática:
|
||||
stat_var_name = f"stat_{network_id}_{instr_uid}_ptrig"
|
||||
stat_var_name_scl = format_variable_name(f'"{stat_var_name}"') # Poner comillas
|
||||
|
||||
# La generación SCL real depende de si usamos una función o lógica explícita.
|
||||
# Usando función estándar (requiere declarar la instancia 'stat_var_name_scl' como P_TRIG en VAR_STAT):
|
||||
# result_scl = f"{stat_var_name_scl}(CLK := {clk_signal_formatted})" # La función devuelve Q
|
||||
# scl_comment = f"// P_TRIG {instr_uid}: {result_scl}"
|
||||
# instruction["scl"] = f"{stat_var_name_scl}(CLK := {clk_signal_formatted}); // Generates edge pulse" # La llamada en sí
|
||||
# result_scl = f"{stat_var_name_scl}.Q" # La salida es el pin Q de la instancia
|
||||
|
||||
# Usando lógica explícita (más portable si no se declaran instancias):
|
||||
result_scl = f"{clk_signal_formatted} AND NOT {mem_bit_scl_formatted}"
|
||||
scl_comment = f"// P_TRIG Logic {instr_uid}: {result_scl}"
|
||||
# La actualización del bit de memoria se hace aparte
|
||||
instruction["scl"] = (
|
||||
f"{mem_bit_scl_formatted} := {clk_signal_formatted}; // Update edge memory bit"
|
||||
)
|
||||
|
||||
else: # Si no es P_TRIG (ej. N_TRIG o simplemente pasando el bit)
|
||||
# Aquí asumimos que es N_TRIG si tiene TemplateValue "Negated" o similar
|
||||
is_negated_pbox = (
|
||||
instruction.get("template_values", {}).get("Negated") == "true"
|
||||
)
|
||||
if is_negated_pbox:
|
||||
# Lógica N_TRIG explícita
|
||||
clk_signal_formatted = rlo_scl # Asumimos que CLK se infiere igual
|
||||
if clk_signal_formatted is None:
|
||||
return False # Esperar CLK
|
||||
|
||||
if (
|
||||
" " in clk_signal_formatted
|
||||
or "AND" in clk_signal_formatted
|
||||
or "OR" in clk_signal_formatted
|
||||
) and not (
|
||||
clk_signal_formatted.startswith("(")
|
||||
and clk_signal_formatted.endswith(")")
|
||||
):
|
||||
clk_signal_formatted = f"({clk_signal_formatted})"
|
||||
|
||||
result_scl = f"NOT {clk_signal_formatted} AND {mem_bit_scl_formatted}"
|
||||
scl_comment = f"// N_TRIG Logic {instr_uid}: {result_scl}"
|
||||
instruction["scl"] = (
|
||||
f"{mem_bit_scl_formatted} := {clk_signal_formatted}; // Update edge memory bit"
|
||||
)
|
||||
# DSTBLK (Obtenemos el nombre RAW para usarlo como pide el usuario)
|
||||
raw_dstblk_name = None
|
||||
dstblk_output_list = instruction.get("outputs", {}).get("DSTBLK", [])
|
||||
if dstblk_output_list and isinstance(dstblk_output_list, list) and len(dstblk_output_list) == 1:
|
||||
dest_access = dstblk_output_list[0]
|
||||
if dest_access.get("type") == "variable":
|
||||
raw_dstblk_name = dest_access.get("name") # Nombre raw del JSON
|
||||
else:
|
||||
# Comportamiento por defecto: pasar el bit de memoria (raro para PBox)
|
||||
print(
|
||||
f"Advertencia: PBox {instr_uid} no parece ser P_TRIG ni N_TRIG. Pasando bit de memoria."
|
||||
)
|
||||
result_scl = mem_bit_scl_formatted
|
||||
scl_comment = f"// PBox {instr_uid} - Passing memory bit: {result_scl}"
|
||||
instruction["scl"] = f"// {scl_comment}" # Solo comentario
|
||||
print(f"Advertencia: Destino DSTBLK de BLKMOV {instr_uid} no es una variable (Tipo: {dest_access.get('type')}).")
|
||||
else:
|
||||
print(f"Error: No se encontró un destino único y válido para DSTBLK en BLKMOV {instr_uid}.")
|
||||
|
||||
# Actualizar el mapa SCL con el resultado booleano del flanco/paso
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = result_scl
|
||||
if raw_dstblk_name is None:
|
||||
instruction["scl"] = f"// ERROR: BLKMOV {instr_uid} sin destino DSTBLK válido."
|
||||
instruction["type"] += "_error"
|
||||
return True
|
||||
|
||||
# ENO sigue al CLK (si existe) o es TRUE por defecto? Asumimos que sigue al CLK si es P/N_TRIG
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = rlo_scl if rlo_scl is not None else "TRUE"
|
||||
# --- Formateo especial para SRCBLK/DSTBLK como pidió el usuario ---
|
||||
# Asume formato "DB".Variable o "Struct".Variable del JSON y lo mantiene
|
||||
# (Esto anula la limpieza normal de format_variable_name para estos parámetros)
|
||||
srcblk_final_str = raw_srcblk_name if raw_srcblk_name else "_ERROR_SRC_"
|
||||
dstblk_final_str = raw_dstblk_name if raw_dstblk_name else "_ERROR_DST_"
|
||||
|
||||
# --- Generar SCL Exacto Solicitado ---
|
||||
scl_core = (
|
||||
f"{retval_target_scl} := BLKMOV(SRCBLK := {srcblk_final_str}, "
|
||||
f"DSTBLK => {dstblk_final_str}); "
|
||||
f"// ADVERTENCIA: BLKMOV usado directamente, probablemente no compile!"
|
||||
)
|
||||
|
||||
# Añadir condición EN (usando la representación SCL obtenida para EN)
|
||||
scl_final = (
|
||||
f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
|
||||
)
|
||||
|
||||
# --- Actualizar Instrucción y Mapa SCL ---
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Propagar ENO (igual que EN)
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl
|
||||
|
||||
# Propagar el valor de retorno (el contenido de la variable asignada a RET_VAL)
|
||||
map_key_ret_val = (network_id, instr_uid, "RET_VAL")
|
||||
scl_map[map_key_ret_val] = retval_target_scl # El valor es lo que sea que se asigne
|
||||
|
||||
return True
|
||||
|
||||
# ... (Asegúrate de que esta función está registrada en processor_map como antes) ...
|
||||
|
||||
def process_o(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
|
@ -890,7 +930,6 @@ def process_o(instruction, network_id, scl_map, access_map):
|
|||
# La instrucción 'O' no tiene ENO propio, propaga el resultado por 'out'
|
||||
return True
|
||||
|
||||
|
||||
def process_call(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction.get("type", "") # Usar get con default
|
||||
|
@ -1008,7 +1047,6 @@ def process_call(instruction, network_id, scl_map, access_map):
|
|||
|
||||
return True
|
||||
|
||||
|
||||
# --- NUEVO: Procesador de Agrupación (Refinado) ---
|
||||
def process_group_ifs(instruction, network_id, scl_map, access_map):
|
||||
"""
|
||||
|
@ -1235,28 +1273,32 @@ def process_json_to_scl(json_filepath):
|
|||
base_processors = [
|
||||
process_convert,
|
||||
process_mod,
|
||||
process_blkmov,
|
||||
process_eq,
|
||||
process_contact,
|
||||
process_o,
|
||||
process_pbox,
|
||||
process_edge_detector, # Usar la nueva función unificada
|
||||
process_add,
|
||||
process_move,
|
||||
process_call,
|
||||
process_coil,
|
||||
# Añadir aquí nuevos procesadores base para otros tipos de instrucciones
|
||||
# ... otros procesadores base ...
|
||||
]
|
||||
# Crear mapa por nombre de tipo original (en minúsculas)
|
||||
processor_map = {}
|
||||
for func in base_processors:
|
||||
# Extraer tipo del nombre de la función (p.ej., 'process_contact' -> 'contact')
|
||||
match = re.match(r"process_(\w+)", func.__name__)
|
||||
if match:
|
||||
type_name = match.group(1).lower()
|
||||
# Manejar casos especiales como 'call' que puede ser FC o FB
|
||||
if type_name == "call":
|
||||
processor_map["call_fc"] = func
|
||||
processor_map["call_fb"] = func
|
||||
processor_map["call"] = func # Genérico por si acaso
|
||||
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
|
||||
elif type_name == "blkmov":
|
||||
processor_map[type_name] = process_blkmov # Usar la nueva función BLKMOV
|
||||
else:
|
||||
processor_map[type_name] = func
|
||||
|
||||
|
@ -1308,20 +1350,10 @@ def process_json_to_scl(json_filepath):
|
|||
|
||||
if func_to_call:
|
||||
try:
|
||||
changed = False
|
||||
# Pasar la lista de lógica completa solo si es necesario (PBox)
|
||||
if func_to_call == process_pbox:
|
||||
changed = func_to_call(
|
||||
instruction,
|
||||
network_id,
|
||||
scl_map,
|
||||
access_map,
|
||||
network_logic,
|
||||
)
|
||||
else:
|
||||
changed = func_to_call(
|
||||
instruction, network_id, scl_map, access_map
|
||||
)
|
||||
changed = func_to_call(
|
||||
instruction, network_id, scl_map, access_map
|
||||
)
|
||||
|
||||
if changed:
|
||||
made_change_in_base_pass = True
|
||||
|
@ -1447,7 +1479,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 = "BlenderCtrl__Main" # 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):
|
||||
|
|
|
@ -197,7 +197,7 @@ def generate_scl(processed_json_filepath, output_scl_filepath):
|
|||
# --- Ejecución ---
|
||||
if __name__ == "__main__":
|
||||
|
||||
xml_file = "BlenderCtrl__Main.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
|
||||
|
|
Loading…
Reference in New Issue