Mejorado simpre de parsing de SCL a SCL

This commit is contained in:
Miguel 2025-04-20 02:27:03 +02:00
parent c22f98d865
commit 4e3aba9a2a
9 changed files with 4510 additions and 66 deletions

105
BlenderCtrl_MFM Command.scl Normal file
View File

@ -0,0 +1,105 @@
FUNCTION "BlenderCtrl_MFM Command" : Void
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : 'Author'
FAMILY : TASK2
NAME : 'Name'
VERSION : 1.0
VAR_INPUT
mResetWaterTot : Bool;
mResetSyrupTot : Bool;
mResetCO2Tot : Bool;
mResetProductTot : Bool;
END_VAR
VAR_TEMP
mWaterVFMCtrl : Int;
mSyrupMFMCtrl : Int;
mCO2MFMCtrl : Int;
mProductMFMCtrl : Int;
END_VAR
BEGIN
IF #mResetWaterTot THEN
#mWaterVFMCtrl := 1 ;
ELSE
#mWaterVFMCtrl := 0 ;
END_IF;
IF #mResetSyrupTot THEN
#mSyrupMFMCtrl := 1 ;
ELSE
#mSyrupMFMCtrl := 0 ;
END_IF;
IF #mResetCO2Tot THEN
#mCO2MFMCtrl := 1 ;
ELSE
#mCO2MFMCtrl := 0 ;
END_IF;
IF #mResetProductTot THEN
#mProductMFMCtrl := 1 ;
ELSE
#mProductMFMCtrl := 0 ;
END_IF;
CASE #mWaterVFMCtrl OF
1: "P_FTN301_Tot_Ctrl" := 01; // Reset Totalizer
2: "P_FTN301_Tot_Ctrl" := 02 ; // Preset Totalizer
ELSE:
"P_FTN301_Tot_Ctrl" := 00;
END_CASE;
IF "gSyrupRoomEn" THEN
CASE #mSyrupMFMCtrl OF
1: "P_FTP302_Tot_Ctrl" := 01; (* Reset Totalizer 1*)
2: "P_FTP302_Tot_Ctrl" := 02; (* Reset Totalizer 2*)
3: "P_FTP302_Tot_Ctrl" := 03; (* Reset Totalizer 1 & 2*)
4: "P_FTP302_Tot_Ctrl" := 04; (* Zeropoint Adjust *)
5: "P_FTP302_Tot_Ctrl" := 05; (* Positive Zero Return *)
6: "P_FTP302_Tot_Ctrl" := 06; (* Negative Zero Return *)
ELSE:
"P_FTP302_Tot_Ctrl" := 00;
END_CASE;
END_IF;
CASE #mCO2MFMCtrl OF
1: "P_FTM303_Tot_Ctrl" := 01; (* Reset Totalizer 1*)
2: "P_FTM303_Tot_Ctrl" := 02; (* Reset Totalizer 2 *)
3: "P_FTM303_Tot_Ctrl" := 03; (* Reset Totalizer 1 & 2*)
4: "P_FTM303_Tot_Ctrl" := 04; (* Zeropoint Adjust *)
5: "P_FTM303_Tot_Ctrl" := 05; (* Positive Zero Return *)
6: "P_FTM303_Tot_Ctrl" := 06; (* Negative Zero Return *)
ELSE:
"P_FTM303_Tot_Ctrl" := 00;
END_CASE;
(*CASE mProductMFMCtrl OF
1: gProductTotCtrl_Node17 := 01; (* Reset Totalizer 1*)
2: gProductTotCtrl_Node17 := 02 ; (* Preset Totalizer1 *)
ELSE
gProductTotCtrl_Node17 := 00;
END_CASE;*)
END_FUNCTION

1711
BlenderPIDCtrl__Loop.xml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
// Block Name (Original): BlenderPIDCtrl__Loop
// Block Number: 1729
// Original Language: LAD
// Block Comment: TASK1 PID
FUNCTION_BLOCK "BlenderPIDCtrl__Loop"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_STAT_STATIC
PID_1_300ms : Bool;
PID_2_300ms : Bool;
PID_3_300ms : Bool;
PID_4_300ms : Bool;
PID_5_300ms : Bool;
PID_6_300ms : Bool;
Flow_Meter_Error_RETVAL : Real;
PID_FF_Calc : "BlenderPID_PIDFFCalc";
PID_Blending_Fault : "BlenderPID_BlendingFault";
PID_Save_Integral : "BlenderPIDCtrl_SaveInteg";
PID_Monitor : "BlenderPIDCtrl_Monitor";
Read_AnalogInput : "BlenderPIDCtrl_ReadAnIn";
END_VAR
VAR_TEMP
END_VAR
BEGIN
// Network 1: Read Analoc Inputs (Original Language: LAD)
"Read_AnalogInput"();
// Network 2: MIX - OB35 scan counter (Original Language: LAD)
// PID Control Time Bit (300ms)
"PID_1_300ms" := Eq("MW1968", 1);
"PID_2_300ms" := Eq("MW1968", 2);
"PID_3_300ms" := Eq("MW1968", 3);
"PID_4_300ms" := Eq("MW1968", 4);
"PID_5_300ms" := Eq("MW1968", 5);
"PID_6_300ms" := Eq("MW1968", 6);
// Network 3: PID Call (Original Language: LAD)
// Water PID
// Syrup PID
// CO2 PID
IF "PID_1_300ms" THEN
"PID_FF_Calc"();
"PID_Blending_Fault"();
BlenderPID_FlowMeterErro();
"PID_Monitor"();
"PID_Save_Integral"();
BlenderPIDCtrl_SaveValve();
END_IF;
IF "PID_1_300ms" AND "HMI_PID"."RMM301"."Config" THEN
"PID_RMM301_Data"();
END_IF;
IF "PID_1_300ms" AND "HMI_PID"."RMP302"."Config" THEN
"PID_RMP302_Data"();
END_IF;
IF "PID_1_300ms" AND "HMI_PID"."RMM303"."Config" THEN
"PID_RMM303_Data"();
END_IF;
IF "PID_1_300ms" AND "HMI_PID"."RMM304"."Config" THEN
"PID_RMM304_Data"();
END_IF;
// Network 4: PID Product Tank Pressure (Original Language: LAD)
IF "PID_2_300ms" AND "HMI_PID"."RVM301"."Config" THEN
"PID_RVM301_Data"();
BlenderPIDCtrl_PresRelea();
END_IF;
// Network 5: Pid Call (Original Language: LAD)
IF "PID_4_300ms" AND "HMI_PID"."RVM319_PRD"."Config" THEN
"PID_RVM319_Data"();
END_IF;
IF "HMI_PID"."RVP303"."Config" AND "PID_4_300ms" THEN
"PID_RVP303_Data"();
END_IF;
IF "HMI_PID"."RVN302"."Config" AND "PID_4_300ms" AND NOT "HMI_PID"."RVN302"."ConfigPID" THEN
"PID_RVN302_Data"();
END_IF;
// Network 6: Filling Head (Original Language: LAD)
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BlendFillSystem" AND "PID_5_300ms" AND "HMI_PID"."PPM303"."Config" THEN
"PID_Filling_Head_Data"();
END_IF;
// Network 7: CIp Heating PID (Original Language: LAD)
IF "PID_6_300ms" AND "HMI_PID"."RVS318"."Config" THEN
"PID_RVS318_Data"();
END_IF;
// Network 8: Write Analog Outputs (Original Language: LAD)
IF "AUX TRUE" THEN
BlenderPIDCtrl_WriteAnOu();
END_IF;
END_FUNCTION_BLOCK

View File

@ -55,7 +55,7 @@
{
"instruction_uid": "SCL_9",
"type": "RAW_SCL_CHUNK",
"scl": "IF \"Blender_Variables\".gSP_H2O <> 0 THEN\n \"Blender_Variables\".gWaterVFMCalcError := \"Blender_Variables\".gWaterVFMMeasError / 100 * \"Blender_Variables\".gSP_H2O;\nEND_IF;\nIF \"Blender_Variables\".gSP_SYR <> 0 THEN\n \"Blender_Variables\".gSyrupMFMCalcError := (\"Blender_Variables\".gSyrupMFMMeasError / 100 + (\"Blender_Variables\".gSyrupMFMZeroStab / (\"Blender_Variables\".gSP_SYR * 60)) / 100) * \"Blender_Variables\".gSP_SYR;\nEND_IF;\nIF \"Blender_Variables\".gSP_CO2 <> 0 THEN\n \"Blender_Variables\".gCO2MFMCalcError := (\"Blender_Variables\".gCO2MFMMeasError / 100 + (\"Blender_Variables\".gCO2MFMZeroStab / (\"Blender_Variables\".gSP_CO2 * 60 / 1000)) / 100) * \"Blender_Variables\".gSP_CO2;\nEND_IF;\n\"mWaterMaxFlow\" := \"Blender_Variables\".gSP_H2O + \"Blender_Variables\".gWaterVFMCalcError;\n\"mWaterMinFlow\" := \"Blender_Variables\".gSP_H2O - \"Blender_Variables\".gWaterVFMCalcError;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mSyrupMaxFlow\" := (\"Blender_Variables\".gSP_SYR + \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\n \"mSyrupMinFlow\" := (\"Blender_Variables\".gSP_SYR - \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\nEND_IF;\nIF \"mSyrupMaxFlow\" <> 0 THEN\n \"mMinRatio\" := \"mWaterMinFlow\" / \"mSyrupMaxFlow\";\nEND_IF;\nIF \"mSyrupMinFlow\" <> 0 THEN\n \"mMaxRatio\" := \"mWaterMaxFlow\" / \"mSyrupMinFlow\";\nEND_IF;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mBevBrixMax\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMinRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\n \"mBevBrixMin\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMaxRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\nEND_IF;\n\"Blender_Variables\".gBlenderBlendMaxError := \"mBevBrixMax\" - \"mBevBrixMin\";\n\"TestLAD\" := \"Blender_Variables\".gBlenderBlendMaxError;"
"scl": "IF \"Blender_Variables\".gSP_H2O <> 0 THEN\n \"Blender_Variables\".gWaterVFMCalcError := \"Blender_Variables\".gWaterVFMMeasError / 100 * \"Blender_Variables\".gSP_H2O;\nEND_IF;\nIF \"Blender_Variables\".gSP_SYR <> 0 THEN\n \"Blender_Variables\".gSyrupMFMCalcError := (\"Blender_Variables\".gSyrupMFMMeasError / 100 + (\"Blender_Variables\".gSyrupMFMZeroStab / (\"Blender_Variables\".gSP_SYR * 60)) / 100) * \"Blender_Variables\".gSP_SYR;\nEND_IF;\nIF \"Blender_Variables\".gSP_CO2 <> 0 THEN\n \"Blender_Variables\".gCO2MFMCalcError := (\"Blender_Variables\".gCO2MFMMeasError / 100 + (\"Blender_Variables\".gCO2MFMZeroStab / (\"Blender_Variables\".gSP_CO2 * 60 / 1000)) / 100) * \"Blender_Variables\".gSP_CO2;\nEND_IF;\n\"mWaterMaxFlow\" := \"Blender_Variables\".gSP_H2O + \"Blender_Variables\".gWaterVFMCalcError;\n\"mWaterMinFlow\" := \"Blender_Variables\".gSP_H2O - \"Blender_Variables\".gWaterVFMCalcError;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mSyrupMaxFlow\" := (\"Blender_Variables\".gSP_SYR + \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\n \"mSyrupMinFlow\" := (\"Blender_Variables\".gSP_SYR - \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\nEND_IF;\nIF \"mSyrupMaxFlow\" <> 0 THEN\n \"mMinRatio\" := \"mWaterMinFlow\" / \"mSyrupMaxFlow\";\nEND_IF;\nIF \"mSyrupMinFlow\" <> 0 THEN\n \"mMaxRatio\" := \"mWaterMaxFlow\" / \"mSyrupMinFlow\";\nEND_IF;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mBevBrixMax\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMinRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\n \"mBevBrixMin\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMaxRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\nEND_IF;\n\"Blender_Variables\".gBlenderBlendMaxError := \"mBevBrixMax\" - \"mBevBrixMin\";\n\"TestLAD\" := \"Blender_Variables\".gBlenderBlendMaxError;"
}
]
}

View File

@ -55,7 +55,7 @@
{
"instruction_uid": "SCL_9",
"type": "RAW_SCL_CHUNK",
"scl": "IF \"Blender_Variables\".gSP_H2O <> 0 THEN\n \"Blender_Variables\".gWaterVFMCalcError := \"Blender_Variables\".gWaterVFMMeasError / 100 * \"Blender_Variables\".gSP_H2O;\nEND_IF;\nIF \"Blender_Variables\".gSP_SYR <> 0 THEN\n \"Blender_Variables\".gSyrupMFMCalcError := (\"Blender_Variables\".gSyrupMFMMeasError / 100 + (\"Blender_Variables\".gSyrupMFMZeroStab / (\"Blender_Variables\".gSP_SYR * 60)) / 100) * \"Blender_Variables\".gSP_SYR;\nEND_IF;\nIF \"Blender_Variables\".gSP_CO2 <> 0 THEN\n \"Blender_Variables\".gCO2MFMCalcError := (\"Blender_Variables\".gCO2MFMMeasError / 100 + (\"Blender_Variables\".gCO2MFMZeroStab / (\"Blender_Variables\".gSP_CO2 * 60 / 1000)) / 100) * \"Blender_Variables\".gSP_CO2;\nEND_IF;\n\"mWaterMaxFlow\" := \"Blender_Variables\".gSP_H2O + \"Blender_Variables\".gWaterVFMCalcError;\n\"mWaterMinFlow\" := \"Blender_Variables\".gSP_H2O - \"Blender_Variables\".gWaterVFMCalcError;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mSyrupMaxFlow\" := (\"Blender_Variables\".gSP_SYR + \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\n \"mSyrupMinFlow\" := (\"Blender_Variables\".gSP_SYR - \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\nEND_IF;\nIF \"mSyrupMaxFlow\" <> 0 THEN\n \"mMinRatio\" := \"mWaterMinFlow\" / \"mSyrupMaxFlow\";\nEND_IF;\nIF \"mSyrupMinFlow\" <> 0 THEN\n \"mMaxRatio\" := \"mWaterMaxFlow\" / \"mSyrupMinFlow\";\nEND_IF;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mBevBrixMax\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMinRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\n \"mBevBrixMin\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMaxRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\nEND_IF;\n\"Blender_Variables\".gBlenderBlendMaxError := \"mBevBrixMax\" - \"mBevBrixMin\";\n\"TestLAD\" := \"Blender_Variables\".gBlenderBlendMaxError;"
"scl": "IF \"Blender_Variables\".gSP_H2O <> 0 THEN\n \"Blender_Variables\".gWaterVFMCalcError := \"Blender_Variables\".gWaterVFMMeasError / 100 * \"Blender_Variables\".gSP_H2O;\nEND_IF;\nIF \"Blender_Variables\".gSP_SYR <> 0 THEN\n \"Blender_Variables\".gSyrupMFMCalcError := (\"Blender_Variables\".gSyrupMFMMeasError / 100 + (\"Blender_Variables\".gSyrupMFMZeroStab / (\"Blender_Variables\".gSP_SYR * 60)) / 100) * \"Blender_Variables\".gSP_SYR;\nEND_IF;\nIF \"Blender_Variables\".gSP_CO2 <> 0 THEN\n \"Blender_Variables\".gCO2MFMCalcError := (\"Blender_Variables\".gCO2MFMMeasError / 100 + (\"Blender_Variables\".gCO2MFMZeroStab / (\"Blender_Variables\".gSP_CO2 * 60 / 1000)) / 100) * \"Blender_Variables\".gSP_CO2;\nEND_IF;\n\"mWaterMaxFlow\" := \"Blender_Variables\".gSP_H2O + \"Blender_Variables\".gWaterVFMCalcError;\n\"mWaterMinFlow\" := \"Blender_Variables\".gSP_H2O - \"Blender_Variables\".gWaterVFMCalcError;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mSyrupMaxFlow\" := (\"Blender_Variables\".gSP_SYR + \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\n \"mSyrupMinFlow\" := (\"Blender_Variables\".gSP_SYR - \"Blender_Variables\".gSyrupMFMCalcError) / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity;\nEND_IF;\nIF \"mSyrupMaxFlow\" <> 0 THEN\n \"mMinRatio\" := \"mWaterMinFlow\" / \"mSyrupMaxFlow\";\nEND_IF;\nIF \"mSyrupMinFlow\" <> 0 THEN\n \"mMaxRatio\" := \"mWaterMaxFlow\" / \"mSyrupMinFlow\";\nEND_IF;\nIF \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN\n \"mBevBrixMax\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMinRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\n \"mBevBrixMin\" := \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupBrix / ((\"mMaxRatio\" / \"HMI_Blender_Parameters\".Actual_Recipe_Parameters._SyrupDensity) + 1);\nEND_IF;\n\"Blender_Variables\".gBlenderBlendMaxError := \"mBevBrixMax\" - \"mBevBrixMin\";\n\"TestLAD\" := \"Blender_Variables\".gBlenderBlendMaxError;"
}
]
}

View File

@ -26,29 +26,29 @@ BEGIN
// Network 1: (Original Language: SCL)
IF "Blender_Variables".gSP_H2O <> 0 THEN
"Blender_Variables".gWaterVFMCalcError := "Blender_Variables".gWaterVFMMeasError / 100 * "Blender_Variables".gSP_H2O;
"Blender_Variables".gWaterVFMCalcError := "Blender_Variables".gWaterVFMMeasError / 100 * "Blender_Variables".gSP_H2O;
END_IF;
IF "Blender_Variables".gSP_SYR <> 0 THEN
"Blender_Variables".gSyrupMFMCalcError := ("Blender_Variables".gSyrupMFMMeasError / 100 + ("Blender_Variables".gSyrupMFMZeroStab / ("Blender_Variables".gSP_SYR * 60)) / 100) * "Blender_Variables".gSP_SYR;
"Blender_Variables".gSyrupMFMCalcError := ("Blender_Variables".gSyrupMFMMeasError / 100 + ("Blender_Variables".gSyrupMFMZeroStab / ("Blender_Variables".gSP_SYR * 60)) / 100) * "Blender_Variables".gSP_SYR;
END_IF;
IF "Blender_Variables".gSP_CO2 <> 0 THEN
"Blender_Variables".gCO2MFMCalcError := ("Blender_Variables".gCO2MFMMeasError / 100 + ("Blender_Variables".gCO2MFMZeroStab / ("Blender_Variables".gSP_CO2 * 60 / 1000)) / 100) * "Blender_Variables".gSP_CO2;
"Blender_Variables".gCO2MFMCalcError := ("Blender_Variables".gCO2MFMMeasError / 100 + ("Blender_Variables".gCO2MFMZeroStab / ("Blender_Variables".gSP_CO2 * 60 / 1000)) / 100) * "Blender_Variables".gSP_CO2;
END_IF;
"mWaterMaxFlow" := "Blender_Variables".gSP_H2O + "Blender_Variables".gWaterVFMCalcError;
"mWaterMinFlow" := "Blender_Variables".gSP_H2O - "Blender_Variables".gWaterVFMCalcError;
IF "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN
"mSyrupMaxFlow" := ("Blender_Variables".gSP_SYR + "Blender_Variables".gSyrupMFMCalcError) / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity;
"mSyrupMinFlow" := ("Blender_Variables".gSP_SYR - "Blender_Variables".gSyrupMFMCalcError) / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity;
"mSyrupMaxFlow" := ("Blender_Variables".gSP_SYR + "Blender_Variables".gSyrupMFMCalcError) / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity;
"mSyrupMinFlow" := ("Blender_Variables".gSP_SYR - "Blender_Variables".gSyrupMFMCalcError) / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity;
END_IF;
IF "mSyrupMaxFlow" <> 0 THEN
"mMinRatio" := "mWaterMinFlow" / "mSyrupMaxFlow";
"mMinRatio" := "mWaterMinFlow" / "mSyrupMaxFlow";
END_IF;
IF "mSyrupMinFlow" <> 0 THEN
"mMaxRatio" := "mWaterMaxFlow" / "mSyrupMinFlow";
"mMaxRatio" := "mWaterMaxFlow" / "mSyrupMinFlow";
END_IF;
IF "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity <> 0 THEN
"mBevBrixMax" := "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupBrix / (("mMinRatio" / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity) + 1);
"mBevBrixMin" := "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupBrix / (("mMaxRatio" / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity) + 1);
"mBevBrixMax" := "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupBrix / (("mMinRatio" / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity) + 1);
"mBevBrixMin" := "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupBrix / (("mMaxRatio" / "HMI_Blender_Parameters".Actual_Recipe_Parameters._SyrupDensity) + 1);
END_IF;
"Blender_Variables".gBlenderBlendMaxError := "mBevBrixMax" - "mBevBrixMin";
"TestLAD" := "Blender_Variables".gBlenderBlendMaxError;

View File

@ -247,101 +247,120 @@ def parse_call(call_element):
def reconstruct_scl_from_tokens(st_node):
"""
Reconstruye una cadena SCL a partir de los elementos hijos
de un nodo <StructuredText>, manejando Tokens, Access (Variables y Constantes),
saltos de línea, espacios y comentarios.
Reconstruye SCL desde <StructuredText>, mejorando el manejo de
variables, constantes literales, tokens básicos, espacios y saltos de línea.
"""
if st_node is None:
return "// Error: StructuredText node not found.\n"
scl_parts = []
# Obtener todos los elementos hijos directos en orden
# Usamos '*' para obtener todos los hijos y luego filtramos por tag
children = st_node.xpath("./st:*", namespaces=ns)
for elem in children:
# Obtener el nombre local de la etiqueta sin el namespace
tag = etree.QName(elem.tag).localname
if tag == "Token":
scl_parts.append(elem.get("Text", ""))
elif tag == "Blank":
scl_parts.append(" " * int(elem.get("Num", 1)))
# Añadir espacios simples, evitar múltiples si ya hay uno antes/después
if not scl_parts or not scl_parts[-1].endswith(' '):
scl_parts.append(" " * int(elem.get("Num", 1)))
elif int(elem.get("Num", 1)) > 1: # Añadir extras si son más de 1
scl_parts.append(" " * (int(elem.get("Num", 1))-1))
elif tag == "NewLine":
# Limpiar espacios antes del salto de línea real
if scl_parts:
scl_parts[-1] = scl_parts[-1].rstrip()
scl_parts.append("\n")
elif tag == "Access":
scope = elem.get("Scope")
access_str = f"_{scope}_?" # Fallback
access_str = f"/*_ERR_Scope_{scope}_*/" # Fallback más informativo
if scope == "GlobalVariable" or scope == "LocalVariable":
if scope in ["GlobalVariable", "LocalVariable", "TempVariable", "InOutVariable", "InputVariable", "OutputVariable", "ConstantVariable"]: # Tipos comunes de variables
symbol_elem = elem.xpath("./st:Symbol", namespaces=ns)
if symbol_elem:
components = symbol_elem[0].xpath("./st:Component | ./st:Token[@Text='.']", namespaces=ns)
components = symbol_elem[0].xpath("./st:Component", namespaces=ns)
symbol_text_parts = []
for comp in components:
comp_tag = etree.QName(comp.tag).localname
if comp_tag == "Component":
name = comp.get("Name", "_ERR_COMP_")
# Comprobar si necesita comillas (requiere BooleanAttribute)
# Simplificación: Añadir comillas si el nombre original parece tenerlas
has_quotes_elem = comp.xpath("../st:BooleanAttribute[@Name='HasQuotes']/text()", namespaces=ns)
has_quotes = has_quotes_elem and has_quotes_elem[0].lower() == "true"
# Heurística: Usar comillas si HasQuotes=true o si es el primer componente y no es TEMP (#)
if has_quotes or (len(symbol_text_parts) == 0 and not name.startswith('#')):
symbol_text_parts.append(f'"{name}"')
else:
symbol_text_parts.append(name)
for i, comp in enumerate(components):
name = comp.get("Name", "_ERR_COMP_")
# Añadir punto si no es el primer componente
if i > 0:
symbol_text_parts.append(".")
# Manejar índices de array (simplificado)
index_access = comp.xpath("./st:Access", namespaces=ns)
if index_access:
indices_text = [reconstruct_scl_from_tokens(idx_node) for idx_node in index_access] # Llamada recursiva
symbol_text_parts.append(f"[{','.join(indices_text)}]")
# Reconstrucción de comillas (heurística)
has_quotes_elem = comp.xpath("../st:BooleanAttribute[@Name='HasQuotes']/text()", namespaces=ns)
has_quotes = has_quotes_elem and has_quotes_elem[0].lower() == "true"
is_temp = name.startswith('#')
elif comp_tag == "Token": # Es un punto
# Asegurarse de no añadir puntos duplicados si ya están en las partes
if symbol_text_parts and symbol_text_parts[-1] != ".":
symbol_text_parts.append(".")
# Limpiar posibles puntos extra al inicio/final o dobles
access_str = "".join(symbol_text_parts).strip('.')
access_str = re.sub(r'\.+', '.', access_str) # Reemplazar múltiples puntos con uno solo
if has_quotes or (i == 0 and not is_temp): # Comillas si HasQuotes o primer componente (no temp)
symbol_text_parts.append(f'"{name}"')
else:
symbol_text_parts.append(name)
# Manejar índices de array (RECURSIVO)
index_access = comp.xpath("./st:Access", namespaces=ns)
if index_access:
# Llama recursivamente para obtener el texto de cada índice
indices_text = [reconstruct_scl_from_tokens(idx_node) for idx_node in index_access]
symbol_text_parts.append(f"[{','.join(indices_text)}]")
access_str = "".join(symbol_text_parts)
elif scope == "LiteralConstant":
constant_elem = elem.xpath("./st:Constant", namespaces=ns)
if constant_elem:
val_elem = constant_elem[0].xpath("./st:ConstantValue/text()", namespaces=ns)
# **CORRECCIÓN CLAVE**: Extraer el valor y usarlo
access_str = val_elem[0] if val_elem else "_ERR_CONSTVAL_"
type_elem = constant_elem[0].xpath("./st:ConstantType/text()", namespaces=ns)
const_type = type_elem[0] if type_elem else ""
const_val = val_elem[0] if val_elem else "_ERR_CONSTVAL_"
# **CORRECCIÓN CLAVE**: Usar el valor extraído
access_str = const_val
# Opcional: añadir prefijos T#, L#, etc. si es necesario
# if const_type == "Time": access_str = f"T#{const_val}"
# elif const_type == "LTime": access_str = f"LT#{const_val}"
# ... otros tipos ...
else:
access_str = "_ERR_NOCONST_"
# Añadir manejo para otros scopes si es necesario (Address, Call, etc.)
# elif scope == "Call": ...
# elif scope == "Address": ...
access_str = "/*_ERR_NOCONST_*/"
# --- Añadir más manejo de scopes aquí si es necesario ---
# elif scope == "Call": access_str = reconstruct_call(elem)
# elif scope == "Expression": access_str = reconstruct_expression(elem)
scl_parts.append(access_str)
elif tag == "Comment" or tag == "LineComment":
# Manejo de comentarios (simplificado - asume texto directo)
comment_text = "".join(elem.xpath(".//text()")).strip()
if tag == "Comment": # Comentario tipo (* *)
if tag == "Comment":
scl_parts.append(f"(* {comment_text} *)")
else: # Comentario tipo //
else:
scl_parts.append(f"// {comment_text}")
# else: # Ignorar otros tipos de nodos por ahora
# pass
# else: Ignorar otros nodos
# Unir todas las partes
# Unir partes, limpiar espacios extra alrededor de operadores y saltos de línea
full_scl = "".join(scl_parts)
# Limpieza básica de formato (puede necesitar ajustes)
lines = [line.rstrip() for line in full_scl.split('\n')]
cleaned_scl = "\n".join(lines)
# Eliminar múltiples líneas vacías consecutivas (opcional)
# import re
# cleaned_scl = re.sub(r'\n\s*\n', '\n\n', cleaned_scl)
return cleaned_scl.strip() # Quitar espacios/saltos al inicio/final
# Re-indentar líneas después de IF/THEN, etc. (Simplificado)
output_lines = []
indent_level = 0
for line in full_scl.split('\n'):
line = line.strip()
if not line: continue # Saltar líneas vacías
# Reducir indentación antes de procesar END_IF, ELSE, etc. (simplificado)
if line.startswith(('END_IF', 'END_WHILE', 'END_FOR', 'END_CASE', 'ELSE', 'ELSIF')):
indent_level = max(0, indent_level - 1)
output_lines.append(" " * indent_level + line) # Aplicar indentación
# Aumentar indentación después de IF, WHILE, FOR, CASE, ELSE, ELSIF (simplificado)
if line.endswith('THEN') or line.endswith('DO') or line.endswith('OF') or line == 'ELSE':
indent_level += 1
# Nota: Esto no maneja bloques BEGIN/END dentro de SCL
return "\n".join(output_lines)
# STL (Statement List) Parser