Compare commits
6 Commits
607e3105b5
...
98dbc7a5d7
Author | SHA1 | Date |
---|---|---|
|
98dbc7a5d7 | |
|
e3b4d413c9 | |
|
27442c88fd | |
|
6228d77d8d | |
|
2d9fd4e80a | |
|
4a30e6d9fd |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -27,360 +27,348 @@ END_VAR
|
|||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Clock Generation
|
||||
// Network 1: Clock Generation (Original Language: LAD)
|
||||
|
||||
Clock_Signal();
|
||||
|
||||
// Network 2: Machine Init
|
||||
// Network 2: Machine Init (Original Language: LAD)
|
||||
|
||||
BlenderCtrl_MachineInit();
|
||||
|
||||
// Network 3: Filler Head
|
||||
// Network 3: Filler Head (Original Language: LAD)
|
||||
|
||||
// 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;
|
||||
|
||||
// Network 4: Emergency Pressed
|
||||
// Network 4: Emergency Pressed (Original Language: LAD)
|
||||
|
||||
// RLO: "gIN_VoltageOk"
|
||||
// Logic moved to Coil 26
|
||||
"gEmergencyPressed" := NOT "gIN_VoltageOk" AND "M19000";
|
||||
"M19000" := "gIN_VoltageOk"; // N_TRIG("gIN_VoltageOk")
|
||||
|
||||
// Network 5: Air and CO2 pressure ok and auxiliary ok
|
||||
// Network 5: Air and CO2 pressure ok and auxiliary ok (Original Language: LAD)
|
||||
|
||||
// RLO: "gIN_LinePressCO2Ok"
|
||||
// RLO: "gWorkshopTest"
|
||||
// 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";
|
||||
"gBlenderSuppliesOk" := (("gIN_LinePressCO2Ok" OR ("gWorkshopTest" AND (NOT "gWorkshop_Co2_Presence")) AND (NOT "gWorkshop_CIP_Signals")) AND "HMI_Digital"."_PAL_S11"."Filtered") OR ("gIN_LinePressCO2Ok" OR ("gWorkshopTest" AND (NOT "gWorkshop_Co2_Presence")) AND (NOT "gWorkshop_CIP_Signals")) AND (NOT "Disable_Bit") AND "gIN_VoltageOk";
|
||||
|
||||
// Network 6: Blender State Num
|
||||
// Network 6: Blender State Num (Original Language: LAD)
|
||||
|
||||
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 0;
|
||||
|
||||
// Network 7: Delay Power On
|
||||
// Network 7: Delay Power On (Original Language: LAD)
|
||||
|
||||
// RLO: "FirstScan"
|
||||
"mDelayPowerOnTmr"(IN := "FirstScan", PT := S5T#2S); // TODO: Declarar "mDelayPowerOnTmr" : TP; en VAR_STAT o VAR
|
||||
|
||||
// Network 8: Production Mode
|
||||
// Network 8: Production Mode (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Variables_Status"."System"."Blender_Prod_CIP"
|
||||
"gBlenderProdMode" := "HMI_Variables_Status"."System"."Blender_Prod_CIP";
|
||||
|
||||
// Network 9: CIp Mode
|
||||
// Network 9: CIp Mode (Original Language: LAD)
|
||||
|
||||
// RLO: (NOT "HMI_Variables_Status"."System"."Blender_Prod_CIP")
|
||||
"gBlenderCIPMode" := (NOT "HMI_Variables_Status"."System"."Blender_Prod_CIP");
|
||||
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 19;
|
||||
IF (NOT "HMI_Variables_Status"."System"."Blender_Prod_CIP") THEN
|
||||
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 19;
|
||||
END_IF;
|
||||
|
||||
// Network 10: Error Faults
|
||||
// Network 10: Error Faults (Original Language: LAD)
|
||||
|
||||
// RLO: (NOT "AUX FALSE")
|
||||
IF (NOT "AUX FALSE") THEN
|
||||
"HMI_Variables_Status"."Meters"."QTM3012_PRD_Fault" := FALSE;
|
||||
END_IF;
|
||||
IF (NOT "AUX FALSE") THEN
|
||||
"gmPDS2000_Error_Fault" := FALSE;
|
||||
END_IF;
|
||||
IF (NOT "AUX FALSE") THEN
|
||||
"HMI_Variables_Status"."Meters"."QTM3012_PRD_Run" := FALSE;
|
||||
END_IF;
|
||||
IF (NOT "AUX FALSE") THEN
|
||||
"gNoFreezeProductMeter" := FALSE;
|
||||
END_IF;
|
||||
|
||||
// Network 11: Filler Bottle Count Used to push Product
|
||||
// Network 11: Filler Bottle Count Used to push Product (Original Language: LAD)
|
||||
|
||||
// RLO: (NOT "System_RunOut_Variables"."ProdPipeRunOutWaterCount")
|
||||
"System_RunOut_Variables"."ProdPipeRunOutFillerBott" := (NOT "System_RunOut_Variables"."ProdPipeRunOutWaterCount");
|
||||
|
||||
// Network 12: Water Bypass Enable
|
||||
// Network 12: Water Bypass Enable (Original Language: LAD)
|
||||
|
||||
// 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 (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
|
||||
// Network 13: Still Water Bypass (Original Language: LAD)
|
||||
|
||||
// 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 (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
|
||||
// Network 14: Manual Syrup Drain Valve Open - Operator Alarm (Original Language: LAD)
|
||||
|
||||
// RLO: "gSyrupRoomEn"
|
||||
// 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 (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");
|
||||
"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 (((("gSyrupRoomEn" AND (NOT "gIN_HVP301_Aux")) AND "gBlenderCIPMode") AND "gIN_CIP_CIPRunning") AND "Procedure_Variables"."Blender_Run"."Running");
|
||||
|
||||
// Network 15: Manual Syrup Drain Valve Open - Operator Alarm
|
||||
// Network 15: Manual Syrup Drain Valve Open - Operator Alarm (Original Language: LAD)
|
||||
|
||||
// RLO: "gIN_HVM302_Aux"
|
||||
"mHVM302_Dly"(IN := "gIN_HVM302_Aux", PT := S5T#1S); // TODO: Declarar "mHVM302_Dly" : TON; en VAR_STAT o VAR
|
||||
"gHVM302_Open" := "mHVM302_Dly".Q;
|
||||
|
||||
// Network 16: Maselli Control
|
||||
// Network 16: Maselli Control (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 6 THEN
|
||||
Maselli_PA_Control();
|
||||
END_IF;
|
||||
|
||||
// Network 17: mPDS Control
|
||||
// Network 17: mPDS Control (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 5 THEN
|
||||
mPDS_PA_Control();
|
||||
END_IF;
|
||||
|
||||
// Network 18: mPDS Syrup Control
|
||||
// Network 18: mPDS Syrup Control (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" THEN
|
||||
mPDS_SYR_PA_Control();
|
||||
END_IF;
|
||||
|
||||
// Network 19: Co2 Analog Input
|
||||
// Network 19: Co2 Analog Input (Original Language: LAD)
|
||||
// GetProdBrixCO2_FromAnalogIn
|
||||
// CALL "GetProdBrixCO2_FromAn"
|
||||
// NOP 0
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_BrixMeter"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_MeterType" = 3 THEN
|
||||
GetProdBrixCO2_Anal_Inpt();
|
||||
END_IF;
|
||||
|
||||
// Network 20: Quality
|
||||
// Network 20: Quality (Original Language: LAD)
|
||||
|
||||
ProductQuality();
|
||||
|
||||
// Network 21: Input Data
|
||||
// Network 21: Input Data (Original Language: LAD)
|
||||
|
||||
"Input_Data"();
|
||||
|
||||
// Network 22: Sel Brix Source Check
|
||||
// Network 22: Sel Brix Source Check (Original Language: LAD)
|
||||
|
||||
SelCheckBrixSource();
|
||||
|
||||
// Network 23: Check Water Cooling System Temperature
|
||||
// Network 23: Check Water Cooling System Temperature (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_InverterRecirPumpPPM306"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_InverterRecirPumpPPM306" THEN
|
||||
CTRLCoolingSystem();
|
||||
END_IF;
|
||||
|
||||
// Network 24: Tank Level
|
||||
// Network 24: Tank Level (Original Language: LAD)
|
||||
|
||||
TankLevel();
|
||||
|
||||
// Network 25: Production ONS
|
||||
// Network 25: Production ONS (Original Language: LAD)
|
||||
|
||||
// RLO: "gBlenderProdMode"
|
||||
// // PBox 26 - Passing memory bit: "M19001"
|
||||
// RLO: "M19001" AND (NOT "mDelayPowerOnTmr")
|
||||
"gProductionONS" := "M19001" AND (NOT "mDelayPowerOnTmr");
|
||||
// PBox Logic moved to consumer Coil
|
||||
"gProductionONS" := ("gBlenderProdMode" AND NOT "M19001") AND (NOT "mDelayPowerOnTmr");
|
||||
|
||||
// Network 26: Blender Prod Mode Init
|
||||
// Network 26: Blender Prod Mode Init (Original Language: LAD)
|
||||
|
||||
// RLO: "gProductionONS"
|
||||
// RLO: "Procedure_Variables"."Blender_Rinse"."ONS_Done"
|
||||
// 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
|
||||
// Network 27: Rinse ONS (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Variables_Status"."System"."Blender_Prod_CIP"
|
||||
// // PBox 26 - Passing memory bit: "M19002"
|
||||
// RLO: "M19002" AND (NOT "mDelayPowerOnTmr")
|
||||
"gRinseONS" := "M19002" AND (NOT "mDelayPowerOnTmr");
|
||||
// PBox Logic moved to consumer Coil
|
||||
"gRinseONS" := ("HMI_Variables_Status"."System"."Blender_Prod_CIP" AND NOT "M19002") AND (NOT "mDelayPowerOnTmr");
|
||||
|
||||
// Network 28: CIP ONS
|
||||
// Network 28: CIP ONS (Original Language: LAD)
|
||||
|
||||
// RLO: "gBlenderCIPMode"
|
||||
// // PBox 26 - Passing memory bit: "M19003"
|
||||
// RLO: "M19003" AND (NOT "mDelayPowerOnTmr")
|
||||
"gCIPONS" := "M19003" AND (NOT "mDelayPowerOnTmr");
|
||||
// PBox Logic moved to consumer Coil
|
||||
"gCIPONS" := ("gBlenderCIPMode" AND NOT "M19003") AND (NOT "mDelayPowerOnTmr");
|
||||
|
||||
// Network 29: CIp Mode Init
|
||||
// Network 29: CIp Mode Init (Original Language: LAD)
|
||||
|
||||
// RLO: "gCIPONS"
|
||||
IF "gCIPONS" THEN
|
||||
BlenderCtrl_CIPModeInit();
|
||||
END_IF;
|
||||
|
||||
// Network 30: Reset SPWords
|
||||
// Network 30: Reset SPWords (Original Language: LAD)
|
||||
|
||||
BlenderCtrl_ResetSPWord();
|
||||
|
||||
// Network 31: Blender Run Control
|
||||
// Network 31: Blender Run Control (Original Language: LAD)
|
||||
|
||||
BlenderRun__Control();
|
||||
|
||||
// Network 32: Tank Pressure Control
|
||||
// Network 32: Tank Pressure Control (Original Language: LAD)
|
||||
|
||||
Prod_Tank_PressCtrl();
|
||||
|
||||
// Network 33: Balaiage
|
||||
// Network 33: Balaiage (Original Language: LAD)
|
||||
|
||||
Baialage();
|
||||
|
||||
// Network 34: First Production
|
||||
// Network 34: First Production (Original Language: LAD)
|
||||
|
||||
"FirstProduction_Data"();
|
||||
|
||||
// Network 35: CIP MAIN Calling
|
||||
// Network 35: CIP MAIN Calling (Original Language: LAD)
|
||||
|
||||
CIPMain();
|
||||
|
||||
// Network 36: Blender Rinse
|
||||
// Network 36: Blender Rinse (Original Language: LAD)
|
||||
|
||||
BlenderRinse();
|
||||
|
||||
// Network 37: Safeties
|
||||
// Network 37: Safeties (Original Language: LAD)
|
||||
|
||||
Safeties();
|
||||
|
||||
// Network 38: Instrument Scanner
|
||||
// Network 38: Instrument Scanner (Original Language: LAD)
|
||||
|
||||
Instrument_Scanner();
|
||||
|
||||
// Network 39: Vacuum Control
|
||||
// Network 39: Vacuum Control (Original Language: LAD)
|
||||
|
||||
VacuumCtrl();
|
||||
|
||||
// Network 40: Syrup Room Control
|
||||
// Network 40: Syrup Room Control (Original Language: LAD)
|
||||
|
||||
SyrupRoomCtrl();
|
||||
|
||||
// Network 41: Blend Procedure Data
|
||||
// Network 41: Blend Procedure Data (Original Language: LAD)
|
||||
|
||||
// RLO: (NOT "mDelayPowerOnTmr")
|
||||
IF (NOT "mDelayPowerOnTmr") THEN
|
||||
"Blender_Procedure Data"();
|
||||
END_IF;
|
||||
|
||||
// Network 42: Pneumatic Valve Control
|
||||
// Network 42: Pneumatic Valve Control (Original Language: LAD)
|
||||
|
||||
Pneumatic_Valve_Ctrl();
|
||||
|
||||
// Network 43: Pumps Control
|
||||
// Network 43: Pumps Control (Original Language: LAD)
|
||||
|
||||
PumpsControl();
|
||||
|
||||
// Network 44: Prod Report Manager
|
||||
// Network 44: Prod Report Manager (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Report"
|
||||
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_Report" THEN
|
||||
ProdReportManager();
|
||||
END_IF;
|
||||
|
||||
// Network 45: Outputs
|
||||
// Network 45: Outputs (Original Language: LAD)
|
||||
|
||||
Output();
|
||||
|
||||
// Network 46: SLIM BLOCK
|
||||
// Network 46: SLIM BLOCK (Original Language: LAD)
|
||||
|
||||
SLIM_Block();
|
||||
|
||||
// Network 47: Interlocking Panel 1
|
||||
// Network 47: Interlocking Panel 1 (Original Language: LAD)
|
||||
|
||||
Interlocking_Panel_1();
|
||||
|
||||
// Network 48: Filler Control
|
||||
// Network 48: Filler Control (Original Language: LAD)
|
||||
|
||||
FillerControl();
|
||||
|
||||
// Network 49: Blender Ctrl Update PWORD
|
||||
// Network 49: Blender Ctrl Update PWORD (Original Language: LAD)
|
||||
|
||||
BlenderCtrl_UpdatePWord();
|
||||
|
||||
// Network 50: ResetTotalizer
|
||||
// Network 50: ResetTotalizer (Original Language: LAD)
|
||||
|
||||
// RLO: "gBlendResetTotalizer"
|
||||
"mResetTotalizerTmr"(IN := "gBlendResetTotalizer", PT := S5T#2S); // TODO: Declarar "mResetTotalizerTmr" : TP; en VAR_STAT o VAR
|
||||
|
||||
// Network 51: ResetWaterTot
|
||||
// Network 51: ResetWaterTot (Original Language: LAD)
|
||||
|
||||
// RLO: "gFTN301_ResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
"mResetFTN301TotTmr"(IN := "gFTN301_ResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetFTN301TotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetWaterTot" := "mResetFTN301TotTmr".Q;
|
||||
|
||||
// Network 52: Water VFM Reset Totalizer
|
||||
// Network 52: Water VFM Reset Totalizer (Original Language: LAD)
|
||||
|
||||
// RLO: "gFTN301_ResetTot"
|
||||
IF "gFTN301_ResetTot" THEN
|
||||
"gFTN301_ResetTot" := FALSE;
|
||||
END_IF;
|
||||
|
||||
// Network 53: ResetCO2Tot
|
||||
// Network 53: ResetCO2Tot (Original Language: LAD)
|
||||
|
||||
// RLO: "gFTP302_ResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
"mResetFTP302TotTmr"(IN := "gFTP302_ResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetFTP302TotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetSyrupTot" := "mResetFTP302TotTmr".Q AND "gSyrupRoomEn";
|
||||
|
||||
// Network 54: Syrup MFM Reset Totalizer
|
||||
// Network 54: Syrup MFM Reset Totalizer (Original Language: LAD)
|
||||
|
||||
// RLO: "gFTP302_ResetTot"
|
||||
IF "gFTP302_ResetTot" THEN
|
||||
"gFTP302_ResetTot" := FALSE;
|
||||
END_IF;
|
||||
|
||||
// Network 55: ResetProductTot
|
||||
// Network 55: ResetProductTot (Original Language: LAD)
|
||||
|
||||
// RLO: "gFTM303_ResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
"mResetFTM303TotTmr"(IN := "gFTM303_ResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetFTM303TotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetCO2Tot" := "mResetFTM303TotTmr".Q;
|
||||
|
||||
// Network 56: CO2 MFM Reset Tot
|
||||
// Network 56: CO2 MFM Reset Tot (Original Language: LAD)
|
||||
|
||||
// RLO: "gFTM303_ResetTot"
|
||||
IF "gFTM303_ResetTot" THEN
|
||||
"gFTM303_ResetTot" := FALSE;
|
||||
END_IF;
|
||||
|
||||
// Network 57: ResetCO2Tot
|
||||
// Network 57: ResetCO2Tot (Original Language: LAD)
|
||||
|
||||
// RLO: "gProductMFMResetTot"
|
||||
// RLO: "mResetTotalizerTmr"
|
||||
"mResetProductTotTmr"(IN := "gProductMFMResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetProductTotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetProductTot" := "mResetProductTotTmr".Q;
|
||||
|
||||
// Network 58: Reset Totalizer
|
||||
// Network 58: Reset Totalizer (Original Language: LAD)
|
||||
|
||||
// RLO: "gProductMFMResetTot"
|
||||
IF "gProductMFMResetTot" THEN
|
||||
"gProductMFMResetTot" := FALSE;
|
||||
END_IF;
|
||||
|
||||
// Network 59: Reset Totalizer
|
||||
// Network 59: Reset Totalizer (Original Language: LAD)
|
||||
|
||||
// RLO: "gBlendResetTotalizer"
|
||||
IF "gBlendResetTotalizer" THEN
|
||||
"gBlendResetTotalizer" := FALSE;
|
||||
END_IF;
|
||||
|
||||
// Network 60: Blender Ctrl Command
|
||||
// Network 60: Blender Ctrl Command (Original Language: LAD)
|
||||
|
||||
// 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
|
||||
// Network 61: DP Global Diag (Original Language: LAD)
|
||||
|
||||
CPU_DP_Global_Diag();
|
||||
|
||||
// Network 62: Profibus
|
||||
// Network 62: Profibus (Original Language: LAD)
|
||||
|
||||
Profibus_Network();
|
||||
|
||||
// Network 63: Valve Fault
|
||||
// Network 63: Valve Fault (Original Language: LAD)
|
||||
|
||||
ModValveFault();
|
||||
|
||||
// Network 64: All Auto
|
||||
// Network 64: All Auto (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Command"
|
||||
// RLO: "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Command" AND "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Enable"
|
||||
// NBox Logic moved to consumer Coil
|
||||
IF NOT ("HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Command" AND "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Enable") AND "M19011" THEN
|
||||
BlenderCtrl_All_Auto();
|
||||
END_IF;
|
||||
"HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Light" := "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Command" AND "HMI_Variables_Cmd"."Commands_From_HMI"."F7_DeviceControl"."Enable";
|
||||
|
||||
// Network 65: Ctrl HMI Manual Active
|
||||
// Network 65: Ctrl HMI Manual Active (Original Language: LAD)
|
||||
|
||||
BlenderCtrl_ManualActive();
|
||||
|
||||
// Network 66: Mod Copy Recipe
|
||||
// Network 66: Mod Copy Recipe (Original Language: LAD)
|
||||
|
||||
// RLO: "HMI_Variables_Cmd"."Recipe"."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"
|
||||
"mFP_Recip_Main_Page" := "HMI_Variables_Cmd"."Recipe"."Main_Page";
|
||||
"T_Pulse_Recipe_Edit"(IN := "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "HMI_Variables_Cmd"."Recipe"."Edit", PT := S5T#500ms); // TODO: Declarar "T_Pulse_Recipe_Edit" : TP; en VAR_STAT o VAR
|
||||
IF "T_Pulse_Recipe_Edit".Q AND "T_Pulse_Recipe_Edit" THEN
|
||||
"HMI_Variables_Cmd"."Recipe"."Edit" := FALSE;
|
||||
END_IF;
|
||||
IF "mAux_FP_M700_1" THEN
|
||||
"HMI_Variables_Cmd"."Recipe"."Edit" := TRUE;
|
||||
END_IF;
|
||||
|
||||
// Network 67: to HMI - Recipe Management
|
||||
// Network 67: to HMI - Recipe Management (Original Language: LAD)
|
||||
|
||||
// RLO: "AUX TRUE"
|
||||
IF "AUX TRUE" THEN
|
||||
"RecipeManagement_Data"();
|
||||
END_IF;
|
||||
|
||||
// Network 68: Recipe Calculation
|
||||
// Network 68: Recipe Calculation (Original Language: LAD)
|
||||
|
||||
RecipeCalculation();
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,132 +0,0 @@
|
|||
// Block Name (Original): BlenderRun_ProdTime
|
||||
// Block Number: 2040
|
||||
// Original Language: LAD
|
||||
|
||||
FUNCTION_BLOCK "BlenderRun_ProdTime"
|
||||
{ S7_Optimized_Access := 'TRUE' }
|
||||
VERSION : 0.1
|
||||
|
||||
VAR_INPUT
|
||||
END_VAR
|
||||
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
|
||||
VAR_IN_OUT
|
||||
END_VAR
|
||||
|
||||
VAR_TEMP
|
||||
m1MinONS : Bool;
|
||||
m1HourONS : Bool;
|
||||
Buffer : Bool;
|
||||
mRunMin : Bool;
|
||||
mRunHr : Bool;
|
||||
I_DIRunning_sec : DInt;
|
||||
I_DIRunning_min : DInt;
|
||||
MOD60 : DInt;
|
||||
END_VAR
|
||||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Seconds
|
||||
|
||||
// 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;
|
||||
|
||||
// Network 4: Minute
|
||||
|
||||
"m1MinONS" := "Blender_Variables_Pers"."gProdSec" = 60;
|
||||
|
||||
// Network 5: Minute Counter
|
||||
|
||||
IF "m1MinONS" THEN
|
||||
"Blender_Variables_Pers"."gProdSec" := 0;
|
||||
"Blender_Variables_Pers"."gProdMin" := "Blender_Variables_Pers"."gProdMin" + 1;
|
||||
END_IF;
|
||||
// Logic included in grouped IF (by UID 27)
|
||||
// Logic included in grouped IF (by UID 27)
|
||||
|
||||
// Network 6: Hour
|
||||
|
||||
"m1HourONS" := "Blender_Variables_Pers"."gProdMin" = 60;
|
||||
|
||||
// Network 7: Hour Counter
|
||||
|
||||
IF "m1HourONS" THEN
|
||||
"Blender_Variables_Pers"."gProdMin" := 0;
|
||||
"Blender_Variables_Pers"."gProdHour" := "Blender_Variables_Pers"."gProdHour" + 1;
|
||||
"Blender_Variables_Pers"."gBlendingMaintHour" := "Blender_Variables_Pers"."gBlendingMaintHour" + 1;
|
||||
END_IF;
|
||||
// Logic included in grouped IF (by UID 30)
|
||||
// Logic included in grouped IF (by UID 30)
|
||||
// Logic included in grouped IF (by UID 30)
|
||||
|
||||
// Network 8: Counter reset
|
||||
|
||||
// RLO: "gBlenderCIPMode"
|
||||
// RLO: "gBlenderRinseMode"
|
||||
IF "gBlenderCIPMode" OR "gBlenderRinseMode" THEN
|
||||
"Blender_Variables_Pers"."gProdSec" := 0;
|
||||
"Blender_Variables_Pers"."gProdMin" := 0;
|
||||
"Blender_Variables_Pers"."gProdHour" := 0;
|
||||
END_IF;
|
||||
// Logic included in grouped IF (by UID 31)
|
||||
// Logic included in grouped IF (by UID 31)
|
||||
// Logic included in grouped IF (by UID 31)
|
||||
|
||||
// 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;
|
||||
|
||||
// Network 10: Running Minutes
|
||||
|
||||
"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;
|
||||
// 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;
|
||||
IF "mRunMin" THEN
|
||||
"MOD60" := "I_DIRunning_min" MOD DINT#60;
|
||||
END_IF;
|
||||
IF "MOD60" = DINT#0 THEN
|
||||
"Blender_Variables_Pers"."gRunningMaintHour" := "Blender_Variables_Pers"."gRunningMaintHour" + 1;
|
||||
END_IF;
|
||||
|
||||
// Network 12: Running Hours for Maintenance
|
||||
|
||||
"HMI_Variables_Status"."System"."BlendingMaintHour" := "Blender_Variables_Pers"."gRunningMaintHour";
|
||||
|
||||
END_FUNCTION_BLOCK
|
1436
TestLAD.xml
1436
TestLAD.xml
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
|
@ -27,11 +27,49 @@ END_VAR
|
|||
|
||||
BEGIN
|
||||
|
||||
// Network 1: Filler Head
|
||||
// Network 1: Manual Syrup Drain Valve Open - Operator Alarm (Original Language: LAD)
|
||||
|
||||
// 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!
|
||||
"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 (((("gSyrupRoomEn" AND (NOT "gIN_HVP301_Aux")) AND "gBlenderCIPMode") AND "gIN_CIP_CIPRunning") AND "Procedure_Variables"."Blender_Run"."Running");
|
||||
|
||||
// Network 2: Manual Syrup Drain Valve Open - Operator Alarm (Original Language: LAD)
|
||||
|
||||
"mHVM302_Dly"(IN := "gIN_HVM302_Aux", PT := S5T#1S); // TODO: Declarar "mHVM302_Dly" : TON; en VAR_STAT o VAR
|
||||
"gHVM302_Open" := "mHVM302_Dly".Q;
|
||||
|
||||
// Network 3: ResetTotalizer (Original Language: LAD)
|
||||
|
||||
"mResetTotalizerTmr"(IN := "gBlendResetTotalizer", PT := S5T#2S); // TODO: Declarar "mResetTotalizerTmr" : TP; en VAR_STAT o VAR
|
||||
|
||||
// Network 4: ResetWaterTot (Original Language: LAD)
|
||||
|
||||
"mResetFTN301TotTmr"(IN := "gFTN301_ResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetFTN301TotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetWaterTot" := "mResetFTN301TotTmr".Q;
|
||||
|
||||
// Network 5: ResetCO2Tot (Original Language: LAD)
|
||||
|
||||
"mResetFTP302TotTmr"(IN := "gFTP302_ResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetFTP302TotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetSyrupTot" := "mResetFTP302TotTmr".Q AND "gSyrupRoomEn";
|
||||
|
||||
// Network 6: ResetProductTot (Original Language: LAD)
|
||||
|
||||
"mResetFTM303TotTmr"(IN := "gFTM303_ResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetFTM303TotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetCO2Tot" := "mResetFTM303TotTmr".Q;
|
||||
|
||||
// Network 7: ResetCO2Tot (Original Language: LAD)
|
||||
|
||||
"mResetProductTotTmr"(IN := "gProductMFMResetTot" OR "mResetTotalizerTmr", PT := S5T#2S); // TODO: Declarar "mResetProductTotTmr" : TP; en VAR_STAT o VAR
|
||||
"mResetProductTot" := "mResetProductTotTmr".Q;
|
||||
|
||||
// Network 8: Mod Copy Recipe (Original Language: LAD)
|
||||
|
||||
"mAux_FP_M700_1" := "HMI_Variables_Cmd"."Recipe"."Main_Page" AND (NOT "mFP_Recip_Main_Page");
|
||||
"mFP_Recip_Main_Page" := "HMI_Variables_Cmd"."Recipe"."Main_Page";
|
||||
"T_Pulse_Recipe_Edit"(IN := "HMI_Variables_Cmd"."Recipe"."Main_Page" AND "HMI_Variables_Cmd"."Recipe"."Edit", PT := S5T#500ms); // TODO: Declarar "T_Pulse_Recipe_Edit" : TP; en VAR_STAT o VAR
|
||||
IF "T_Pulse_Recipe_Edit".Q AND "T_Pulse_Recipe_Edit" THEN
|
||||
"HMI_Variables_Cmd"."Recipe"."Edit" := FALSE;
|
||||
END_IF;
|
||||
IF "mAux_FP_M700_1" THEN
|
||||
"HMI_Variables_Cmd"."Recipe"."Edit" := TRUE;
|
||||
END_IF;
|
||||
|
||||
END_FUNCTION_BLOCK
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
# 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.
|
|
@ -1,687 +0,0 @@
|
|||
# -*- 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
|
@ -1,218 +0,0 @@
|
|||
# -*- 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)
|
|
@ -0,0 +1,284 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="AttributeList" type="AttributeList_T"/>
|
||||
<xs:complexType name="AttributeList_T">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="BooleanAttribute"/>
|
||||
<xs:element ref="IntegerAttribute"/>
|
||||
<xs:element ref="RealAttribute"/>
|
||||
<xs:element ref="StringAttribute"/>
|
||||
<xs:element ref="DateAttribute"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
<xs:element name="Blank" type="Blank_T"/>
|
||||
<xs:complexType name="Blank_T">
|
||||
<xs:attribute name="Num" type="xs:positiveInteger" use="optional" default="1"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="BooleanAttribute" type="BooleanAttribute_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A member attribute with a type restriction of boolean.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="BooleanAttribute_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:boolean">
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Exported only with ReadOnly option, ignored during import.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SystemDefined" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>An attribute of attribute, denotes if it is defined by a user or the system itself. In V14, if exists it is always true.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="Comment" type="Comment_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not allowed in STL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:group name="Comment_G">
|
||||
<xs:annotation>
|
||||
<xs:documentation>LAD/FBD: Only for Parts</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element ref="Comment"/>
|
||||
<xs:element ref="LineComment"/>
|
||||
<xs:element ref="Blank"/>
|
||||
<xs:element ref="NewLine"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:group>
|
||||
<xs:complexType name="Comment_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="IntegerAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>For NumBLs in STL. NumBLs is the count of the blank spaces before the actual text in the Comment. This is informative.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="MultiLanguageText" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Inserted" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Denotes if the comment is at the end of the line (using /*/) or inside the line (using (/* */) )</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Exported only with ReadOnly option, ignored during import.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="DateAttribute" type="DateAttribute_T"/>
|
||||
<xs:complexType name="DateAttribute_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:dateTime">
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Exported only with ReadOnly option, ignored during import.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SystemDefined" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>An attribute of attribute, denotes if it is defined by a user or the system itself. In V14, if exists it is always true.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="GUID_TP">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="IntegerAttribute" type="IntegerAttribute_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A member attribute with a type restriction of integer.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="IntegerAttribute_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not for LAD/FBD.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:integer">
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Exported only with ReadOnly option, ignored during import.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SystemDefined" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>An attribute of attribute, denotes if it is defined by a user or the system itself. In V14, if exists it is always true.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Lang_TP">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[a-zA-Z]{2}-[a-zA-Z]{2}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="LineComment" type="LineComment_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not for LAD/FBD </xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="LineComment_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="IntegerAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>For NumBLs in STL. NumBLs is the count of the blank spaces before the actual text in the LineComment. This is informative.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element ref="Text"/>
|
||||
<xs:element ref="Comment"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Inserted" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Denotes if the comment is at the end of the line (using //) or inside the line (using /* */)</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="NoClosingBracket" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="MultiLanguageText" type="MultiLanguageText_T"/>
|
||||
<xs:complexType name="MultiLanguageText_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="Lang" type="Lang_TP" use="required"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="NewLine" type="NewLine_T"/>
|
||||
<xs:complexType name="NewLine_T">
|
||||
<xs:attribute name="Num" type="xs:positiveInteger" use="optional" default="1"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="RealAttribute" type="RealAttribute_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A member attribute with a type restriction of real.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="RealAttribute_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:double">
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Exported only with ReadOnly option, ignored during import.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SystemDefined" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>An attribute of attribute, denotes if it is defined by a user or the system itself. In V14, if exists it is always true.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="SectionName_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="None"/>
|
||||
<xs:enumeration value="Input"/>
|
||||
<xs:enumeration value="Return"/>
|
||||
<xs:enumeration value="Output"/>
|
||||
<xs:enumeration value="InOut"/>
|
||||
<xs:enumeration value="Static"/>
|
||||
<xs:enumeration value="Temp"/>
|
||||
<xs:enumeration value="Constant"/>
|
||||
<xs:enumeration value="Base"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="SimaticName_TP">
|
||||
<xs:restriction base="xs:string"/>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="SimaticType_TE">
|
||||
<xs:restriction base="xs:string"/>
|
||||
</xs:simpleType>
|
||||
<xs:element name="StringAttribute" type="StringAttribute_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A member attribute with a type restriction of string.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="StringAttribute_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Exported only with ReadOnly option, ignored during import.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SystemDefined" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>An attribute of attribute, denotes if it is defined by a user or the system itself. In V14, if exists it is always true.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="Text" type="Text_T"/>
|
||||
<xs:complexType name="Text_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="Token" type="Token_T"/>
|
||||
<xs:group name="Token_G">
|
||||
<xs:choice>
|
||||
<xs:element ref="Token" minOccurs="0"/>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:choice>
|
||||
</xs:group>
|
||||
<xs:complexType name="Token_T">
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:element ref="IntegerAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>For NumBLs. NumBLs is the count of the blank spaces at the start.This is informative.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Text" type="Token_TE" use="required"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Token_TE">
|
||||
<xs:restriction base="xs:string"/>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="VersionString_TP">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[0-9]+(.[0-9]+){0,3}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="ViewInfo" type="ViewInfo_T"/>
|
||||
<xs:complexType name="ViewInfo_T">
|
||||
<xs:attribute name="Start" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="XPos" type="xs:int" use="optional"/>
|
||||
<xs:attribute name="YPos" type="xs:int" use="optional"/>
|
||||
<xs:attribute name="Width" type="xs:int" use="optional"/>
|
||||
<xs:attribute name="Height" type="xs:int" use="optional"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2018. All rights reserved. -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="SnapshotValues" type="SnapshotValues_T"/>
|
||||
<xs:complexType name="SnapshotValues_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Value" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Value" type="Value_T"/>
|
||||
<xs:complexType name="Value_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="Path" type="xs:string" use="required"/>
|
||||
<xs:attribute name="Type" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,162 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2020. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.Common_v3.xsd"/>
|
||||
<xs:simpleType name="Accessibility_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Public"/>
|
||||
<xs:enumeration value="Internal"/>
|
||||
<xs:enumeration value="Protected"/>
|
||||
<xs:enumeration value="Private"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="IndexPath_TP">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="-?\d+(,-?\d+)*(;(-?\d+(,-?\d+)*))?"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Member" type="Member_T"/>
|
||||
<xs:complexType name="Member_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="AttributeList" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Member"/>
|
||||
<xs:element ref="Sections"/>
|
||||
<xs:element ref="StartValue"/>
|
||||
<xs:element ref="Comment"/>
|
||||
<xs:element ref="AssignedProDiagFB"/>
|
||||
<xs:element ref="Subelement"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="Datatype" type="SimaticType_TE" use="required"/>
|
||||
<xs:attribute name="Version" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The version of the library type to use. Previous to this, the version was written inside the Datatype attribute itself, like "dtl:v1.0". Now, this is written in two separate attributes, to mitigate problems with weird names ("dtl:v1.0" could be a UDT name!).</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Remanence" type="Remanence_TE" default="NonRetain"/>
|
||||
<xs:attribute name="Accessibility" type="Accessibility_TE" default="Public"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="MemberAttributes_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="CodeReadOnly">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Write acces only inside function</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="At">
|
||||
<xs:annotation>
|
||||
<xs:documentation>string: Member shares offset with another member in this structure</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="SetPoint">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: Member can be synchronized with work memory</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="UserVisible">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: Editor does not show the member</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="UserReadOnly">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: User cannot change member name</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="UserDeletable">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: Editor does not allow to delete the member</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="HmiAccessible">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: No HMI access, no structure item</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="HmiVisible">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: Filter to reduce the number of members shown in the first place</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="Offset">
|
||||
<xs:annotation>
|
||||
<xs:documentation>integer: </xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="PaddedSize">
|
||||
<xs:annotation>
|
||||
<xs:documentation>integer: </xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="HiddenAssignment">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: Hide assignement at call if matches with PredefinedAssignment</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="PredefinedAssignment">
|
||||
<xs:annotation>
|
||||
<xs:documentation>string: Input for the paramter used when call is placed</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="ReadOnlyAssignment">
|
||||
<xs:annotation>
|
||||
<xs:documentation>boolean: The user cannot change the predefined assignement at the call</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="Remanence_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="SetInIDB"/>
|
||||
<xs:enumeration value="NonRetain"/>
|
||||
<xs:enumeration value="Retain"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Section" type="Section_T"/>
|
||||
<xs:complexType name="Section_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Sections" minOccurs="0" maxOccurs="1">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Base Class</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Member" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Name" type="SectionName_TE" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Sections" type="Sections_T"/>
|
||||
<xs:complexType name="Sections_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="AttributeList" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="Section" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Datatype" type="SimaticType_TE"/>
|
||||
<xs:attribute name="Version" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="StartValue" type="StartValue_T"/>
|
||||
<xs:element name="AssignedProDiagFB" type="xs:string"/>
|
||||
<xs:complexType name="StartValue_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="ConstantName" type="SimaticName_TP"/>
|
||||
<xs:attribute name="IsBulkValue" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="Subelement" type="Subelement_T"/>
|
||||
<xs:complexType name="Subelement_T">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="StartValue"/>
|
||||
<xs:element ref="Comment"/>
|
||||
<xs:element ref="AssignedProDiagFB"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Path" type="IndexPath_TP"/>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,593 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.Common_v3.xsd"/>
|
||||
<xs:element name="AbsoluteOffset" type="AbsoluteOffset_T"/>
|
||||
<xs:complexType name="AbsoluteOffset_T">
|
||||
<xs:attribute name="BitOffset" type="xs:int" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Byte * 8 + Bit</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Type" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Access" type="Access_T"/>
|
||||
<xs:group name="Access_G">
|
||||
<xs:sequence>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element ref="Access"/>
|
||||
<xs:element ref="Token"/>
|
||||
<xs:group ref="Comment_G"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:group>
|
||||
<xs:complexType name="Access_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="IntegerAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for NumBLs. NumBLs is informative. Not for LAD/FBD.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:choice>
|
||||
<xs:element ref="Label"/>
|
||||
<xs:element ref="Constant"/>
|
||||
<xs:element ref="CallInfo">
|
||||
<xs:annotation>
|
||||
<xs:documentation>call of a user block. Not in Graph ActionList.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Instruction">
|
||||
<xs:annotation>
|
||||
<xs:documentation>call of an instruction. Not for LAD/FBD, Graph ActionList.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Indirect">
|
||||
<xs:annotation>
|
||||
<xs:documentation>STL specific</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Statusword"/>
|
||||
<xs:element ref="PredefinedVariable">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Only in SCL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Expression">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SCL specific</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Symbol"/>
|
||||
<xs:element ref="Address">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for absolute addresses</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="DataType"/>
|
||||
<xs:element ref="Reference"/>
|
||||
</xs:choice>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Scope" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="Scope_TE"/>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not allowed in STL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="AccessModifier_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="None"/>
|
||||
<xs:enumeration value="Array"/>
|
||||
<xs:enumeration value="Reference"/>
|
||||
<xs:enumeration value="ReferenceToArray"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Address" type="Address_T"/>
|
||||
<xs:complexType name="Address_T">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="BooleanAttribute"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="Area" type="Area_TE" use="required"/>
|
||||
<xs:attribute name="Type" type="SimaticName_TP" use="optional"/>
|
||||
<xs:attribute name="BlockNumber" type="xs:int" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for DB access</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="BitOffset" type="xs:int" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>In general it is Byte * 8 + Bit. But if it is used for addressing a DB we will find the number of the DB here (e.g. "DB12" ->12).</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false">
|
||||
<xs:annotation>
|
||||
<xs:documentation>if true, the import unnoted it</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Area_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="None"/>
|
||||
<xs:enumeration value="PeripheryInput"/>
|
||||
<xs:enumeration value="PeripheryOutput"/>
|
||||
<xs:enumeration value="Input"/>
|
||||
<xs:enumeration value="Output"/>
|
||||
<xs:enumeration value="Memory"/>
|
||||
<xs:enumeration value="FB"/>
|
||||
<xs:enumeration value="FC"/>
|
||||
<xs:enumeration value="DB">
|
||||
<xs:annotation>
|
||||
<xs:documentation>partly qualified access with DB register</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="DI">
|
||||
<xs:annotation>
|
||||
<xs:documentation>partly qualified access with DI register</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="Timer"/>
|
||||
<xs:enumeration value="Counter"/>
|
||||
<xs:enumeration value="Local">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Classic Local Stack</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="BlockType_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="DB"/>
|
||||
<xs:enumeration value="FB"/>
|
||||
<xs:enumeration value="FC"/>
|
||||
<xs:enumeration value="OB"/>
|
||||
<xs:enumeration value="UDT"/>
|
||||
<xs:enumeration value="FBT"/>
|
||||
<xs:enumeration value="FCT"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="CallInfo" type="CallInfo_T"/>
|
||||
<xs:complexType name="CallInfo_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not for LAD/FBD. </xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="IntegerAttribute">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for BlockNumber. BlockNumber is informative.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="DateAttribute">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for ParameterModifiedTS. ParameterModifiedTS is informative</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Instance"/>
|
||||
<xs:element ref="NamelessParameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:group ref="Token_G" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="Parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="Name" type="SimaticName_TP" use="optional"/>
|
||||
<xs:attribute name="BlockType" type="BlockType_TE" use="required"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Component" type="Component_T"/>
|
||||
<xs:complexType name="Component_T">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:group ref="Comment_G" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SCL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:group>
|
||||
<xs:element ref="Token" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SCL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Access">
|
||||
<xs:annotation>
|
||||
<xs:documentation>For the indices of an array</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="BooleanAttribute" minOccurs="0"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="SliceAccessModifier" type="SliceAccessModifier_TP" default="undef"/>
|
||||
<xs:attribute name="SimpleAccessModifier" type="SimpleAccessModifier_TP" default="None"/>
|
||||
<xs:attribute name="AccessModifier" type="AccessModifier_TE" default="None">
|
||||
<xs:annotation>
|
||||
<xs:documentation>If component has child AccessModifier is Array else AccessModifier is None</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Constant" type="Constant_T"/>
|
||||
<xs:complexType name="Constant_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="ConstantType" minOccurs="0"/>
|
||||
<xs:element ref="ConstantValue" minOccurs="0"/>
|
||||
<xs:element ref="StringAttribute" minOccurs="0" maxOccurs="2">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for Format and FormatFlags. They are informative..</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="BooleanAttribute" minOccurs="0" maxOccurs="2"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Name" type="SimaticName_TP"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="ConstantType" type="ConstantType_T"/>
|
||||
<xs:complexType name="ConstantType_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="Informative" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="ConstantValue" type="ConstantValue_T"/>
|
||||
<xs:complexType name="ConstantValue_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="Informative" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="Expression" type="Expression_T"/>
|
||||
<xs:complexType name="Expression_T">
|
||||
<xs:sequence maxOccurs="unbounded">
|
||||
<xs:choice>
|
||||
<xs:element ref="Access"/>
|
||||
<xs:element ref="Token"/>
|
||||
</xs:choice>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="UId" type="xs:int"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="DataType" type="DataType_T"/>
|
||||
<xs:complexType name="DataType_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="Informative" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Format_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Real"/>
|
||||
<xs:enumeration value="Bin"/>
|
||||
<xs:enumeration value="DecSigned"/>
|
||||
<xs:enumeration value="DecUnsigned"/>
|
||||
<xs:enumeration value="Pointer"/>
|
||||
<xs:enumeration value="CharSequence"/>
|
||||
<xs:enumeration value="DecSequence"/>
|
||||
<xs:enumeration value="Hex"/>
|
||||
<xs:enumeration value="S5Count"/>
|
||||
<xs:enumeration value="Time"/>
|
||||
<xs:enumeration value="Date"/>
|
||||
<xs:enumeration value="TimeOfDay"/>
|
||||
<xs:enumeration value="S5Time"/>
|
||||
<xs:enumeration value="Bool"/>
|
||||
<xs:enumeration value="Oct"/>
|
||||
<xs:enumeration value="Bcd"/>
|
||||
<xs:enumeration value="DateAndTime"/>
|
||||
<xs:enumeration value="String"/>
|
||||
<xs:enumeration value="Any"/>
|
||||
<xs:enumeration value="Number"/>
|
||||
<xs:enumeration value="Char"/>
|
||||
<xs:enumeration value="HexSequence"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="FormatFlags_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="None"/>
|
||||
<xs:pattern value="((Lower|Format|Size|Under|Exp|TypeQualifier)(,\s*)?)*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Indirect" type="Indirect_T"/>
|
||||
<xs:complexType name="Indirect_T">
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Token"/>
|
||||
<xs:group ref="Comment_G"/>
|
||||
</xs:choice>
|
||||
<xs:element ref="Access" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Width" type="Width_TE" use="required"/>
|
||||
<xs:attribute name="Area" type="Area_TE" use="optional"/>
|
||||
<xs:attribute name="Register" type="Register_TE" use="optional"/>
|
||||
<xs:attribute name="BitOffset" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Instance" type="Instance_T"/>
|
||||
<xs:complexType name="Instance_T">
|
||||
<xs:sequence maxOccurs="unbounded">
|
||||
<xs:choice>
|
||||
<xs:element ref="Component"/>
|
||||
<xs:element ref="AbsoluteOffset"/>
|
||||
<xs:element ref="Token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>the DOT; only if separated. Not in Graph ActionList, not in LAD/FBD.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Address"/>
|
||||
</xs:choice>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="UId" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not allowed in STL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Scope" type="Scope_TE" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Instruction" type="Instruction_T"/>
|
||||
<xs:complexType name="Instruction_T">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:group ref="Token_G"/>
|
||||
<xs:element ref="TemplateValue"/>
|
||||
|
||||
<xs:element ref="Instance"/>
|
||||
<xs:element ref="NamelessParameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="Parameter" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Name" use="optional">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="SimaticName_TP">
|
||||
<xs:minLength value="1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Version" type="VersionString_TP"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="UId" type="xs:int"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="InterfaceFlags_TP">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="None"/>
|
||||
<xs:pattern value="((Mandatory|S7_Visible)(,\s*)?)*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Label" type="Label_T"/>
|
||||
<xs:complexType name="Label_T">
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SCL only</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:element ref="BooleanAttribute" minOccurs="0"/>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
<xs:element ref="Token" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Name" type="SimaticName_TP" use="required"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="NamelessParameter" type="NamelessParameter_T"/>
|
||||
<xs:complexType name="NamelessParameter_T">
|
||||
<xs:sequence maxOccurs="unbounded">
|
||||
<xs:element ref="StringAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for InterfaceFlags. InterfaceFlags is informative</xs:documentation>
|
||||
<xs:documentation>The type of the value should be InterfaceFlags_TP</xs:documentation>
|
||||
<xs:documentation>The default value is "S7_Visible"</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:group ref="Access_G"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="UId" type="xs:int"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Parameter" type="Parameter_T"/>
|
||||
|
||||
<xs:complexType name="Parameter_T">
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:element ref="IntegerAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for NumBLs. NumBLs is informative</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="StringAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for InterfaceFlags. InterfaceFlags is informative</xs:documentation>
|
||||
<xs:documentation>The type of the value should be InterfaceFlags_TP</xs:documentation>
|
||||
<xs:documentation>The default value is "S7_Visible"</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="BooleanAttribute" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:group ref="Access_G" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Name" type="SimaticName_TP" use="required"/>
|
||||
<xs:attribute name="Section" type="SectionName_TE" use="optional"/>
|
||||
<xs:attribute name="Type" type="SimaticType_TE"/>
|
||||
<xs:attribute name="TemplateReference" type="xs:string"/>
|
||||
<xs:attribute name="Informative" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="UId" type="xs:int"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="PredefinedVariable" type="PredefinedVariable_T"/>
|
||||
<xs:complexType name="PredefinedVariable_T">
|
||||
<xs:attribute name="Name" type="PredefinedVariable_TE" use="required"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="PredefinedVariable_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="ENO"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Reference" type="Reference_T"/>
|
||||
<xs:complexType name="Reference_T">
|
||||
<xs:sequence>
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SCL</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
<xs:element ref="Token"/>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:element ref="Access"/>
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SCL</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
<xs:element ref="Token"/>
|
||||
</xs:sequence>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Register_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="AR1"/>
|
||||
<xs:enumeration value="AR2"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="Scope_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Undef">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Symbols we do not know what they are</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="GlobalConstant"/>
|
||||
<xs:enumeration value="LocalConstant"/>
|
||||
<xs:enumeration value="GlobalVariable"/>
|
||||
<xs:enumeration value="LocalVariable"/>
|
||||
<xs:enumeration value="Instruction"/>
|
||||
<xs:enumeration value="Label"/>
|
||||
<xs:enumeration value="TypedConstant"/>
|
||||
<xs:enumeration value="AddressConstant"/>
|
||||
<xs:enumeration value="LiteralConstant"/>
|
||||
<xs:enumeration value="AlarmConstant"/>
|
||||
<xs:enumeration value="Address"/>
|
||||
<xs:enumeration value="Statusword"/>
|
||||
<xs:enumeration value="Expression"/>
|
||||
<xs:enumeration value="Unnamed"/>
|
||||
<xs:enumeration value="Call"/>
|
||||
<xs:enumeration value="CallWithType"/>
|
||||
<xs:enumeration value="UserType"/>
|
||||
<xs:enumeration value="SystemType"/>
|
||||
<xs:enumeration value="Reference"/>
|
||||
<xs:enumeration value="PredefinedVariable"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="SimpleAccessModifier_TP">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="None|((Periphery|QualityInformation)(,\s*)?)*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="SimpleType_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="undef"/>
|
||||
<xs:enumeration value="Bool"/>
|
||||
<xs:enumeration value="Byte"/>
|
||||
<xs:enumeration value="Char"/>
|
||||
<xs:enumeration value="Word"/>
|
||||
<xs:enumeration value="Int"/>
|
||||
<xs:enumeration value="DWord"/>
|
||||
<xs:enumeration value="DInt"/>
|
||||
<xs:enumeration value="Real"/>
|
||||
<xs:enumeration value="LReal"/>
|
||||
<xs:enumeration value="Timer"/>
|
||||
<xs:enumeration value="S5Time"/>
|
||||
<xs:enumeration value="ARef"/>
|
||||
<xs:enumeration value="Any"/>
|
||||
<xs:enumeration value="Time"/>
|
||||
<xs:enumeration value="S5Count"/>
|
||||
<xs:enumeration value="Counter"/>
|
||||
<xs:enumeration value="Block_DB"/>
|
||||
<xs:enumeration value="Block_FB"/>
|
||||
<xs:enumeration value="Block_FC"/>
|
||||
<xs:enumeration value="Block_SFB"/>
|
||||
<xs:enumeration value="Block_UDT"/>
|
||||
<xs:enumeration value="Multi_FB"/>
|
||||
<xs:enumeration value="Multi_SFB"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="SliceAccessModifier_TP">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="([xbwdXBWD]\d+)|undef"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Statusword" type="Statusword_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Only for S7-300/400/WinAC</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="Statusword_T">
|
||||
<xs:attribute name="Combination" type="Statusword_TE" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Statusword_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="BR"/>
|
||||
<xs:enumeration value="OV"/>
|
||||
<xs:enumeration value="OS"/>
|
||||
<xs:enumeration value="EQ"/>
|
||||
<xs:enumeration value="NE"/>
|
||||
<xs:enumeration value="GT"/>
|
||||
<xs:enumeration value="LT"/>
|
||||
<xs:enumeration value="GE"/>
|
||||
<xs:enumeration value="LE"/>
|
||||
<xs:enumeration value="UO"/>
|
||||
<xs:enumeration value="NU"/>
|
||||
<xs:enumeration value="STW"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Symbol" type="Symbol_T"/>
|
||||
<xs:complexType name="Symbol_T">
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element ref="Component"/>
|
||||
<xs:element ref="Address"/>
|
||||
<xs:element ref="AbsoluteOffset"/>
|
||||
<xs:element ref="Token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SCL.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Access"/>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="UId" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not allowed in STL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Scope" type="Scope_TE"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="TemplateType_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Cardinality"/>
|
||||
<xs:enumeration value="Type"/>
|
||||
<xs:enumeration value="Operation"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="TemplateValue" type="TemplateValue_T"/>
|
||||
<xs:complexType name="TemplateValue_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="Name" type="SimaticName_TP" use="required"/>
|
||||
<xs:attribute name="Type" type="TemplateType_TE" use="required"/>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Width_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="None"/>
|
||||
<xs:enumeration value="Bit"/>
|
||||
<xs:enumeration value="Byte"/>
|
||||
<xs:enumeration value="Word"/>
|
||||
<xs:enumeration value="Offset"/>
|
||||
<xs:enumeration value="Double"/>
|
||||
<xs:enumeration value="Pointer"/>
|
||||
<xs:enumeration value="Long"/>
|
||||
<xs:enumeration value="Any"/>
|
||||
<xs:enumeration value="Block"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.PlcBlocks.Access_v4.xsd"/>
|
||||
<xs:element name="LabelDeclaration" type="LabelDeclaration_T"/>
|
||||
<xs:complexType name="LabelDeclaration_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="IntegerAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for NumBLs. NumBLs is informative</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Label"/>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:element ref="Token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>the COLON; only if separated</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="UId" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not allowed in STL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,350 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.PlcBlocks.Access_v4.xsd"/>
|
||||
<xs:include schemaLocation="SW.PlcBlocks.LADFBD_v4.xsd"/>
|
||||
<xs:complexType name="Action_T">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Access"/>
|
||||
<xs:element ref="Token"/>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="Event" type="Event_TE"/>
|
||||
<xs:attribute name="Interlock" type="xs:boolean"/>
|
||||
<xs:attribute name="Qualifier" type="Qualifier_TE"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Event_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value=""/>
|
||||
<xs:enumeration value="A1"/>
|
||||
<xs:enumeration value="L0"/>
|
||||
<xs:enumeration value="L1"/>
|
||||
<xs:enumeration value="R1"/>
|
||||
<xs:enumeration value="S0"/>
|
||||
<xs:enumeration value="S1"/>
|
||||
<xs:enumeration value="V0"/>
|
||||
<xs:enumeration value="V1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="Qualifier_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value=""/>
|
||||
<xs:enumeration value="CD"/>
|
||||
<xs:enumeration value="CR"/>
|
||||
<xs:enumeration value="CS"/>
|
||||
<xs:enumeration value="CU"/>
|
||||
<xs:enumeration value="D"/>
|
||||
<xs:enumeration value="L"/>
|
||||
<xs:enumeration value="N"/>
|
||||
<xs:enumeration value="ON"/>
|
||||
<xs:enumeration value="OFF"/>
|
||||
<xs:enumeration value="R"/>
|
||||
<xs:enumeration value="S"/>
|
||||
<xs:enumeration value="TD"/>
|
||||
<xs:enumeration value="TF"/>
|
||||
<xs:enumeration value="TL"/>
|
||||
<xs:enumeration value="TR"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Actions" type="Actions_T"/>
|
||||
<xs:complexType name="Actions_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Title" minOccurs="0"/>
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Action"/>
|
||||
</xs:sequence>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="AlarmSupportingLanguageModule_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Title" minOccurs="0"/>
|
||||
<xs:element ref="AlarmText" minOccurs="0"/>
|
||||
<xs:element ref="FlgNet"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="ProgrammingLanguage" type="ProgrammingLanguage_TE" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="AlarmText" type="AlarmText_T"/>
|
||||
<xs:complexType name="AlarmText_T">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Temporary change for enable of empty alarm text because of the graph alarm handling reconstruction.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:element ref="MultiLanguageText"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Branch_T">
|
||||
<xs:attribute name="Number" type="xs:int" use="required"/>
|
||||
<xs:attribute name="Type" type="Branch_TE" use="required"/>
|
||||
<xs:attribute name="Cardinality" type="xs:int" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Branch_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="SimBegin"/>
|
||||
<xs:enumeration value="SimEnd"/>
|
||||
<xs:enumeration value="AltBegin"/>
|
||||
<xs:enumeration value="AltEnd"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Branches" type="Branches_T"/>
|
||||
<xs:complexType name="Branches_T">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Branch"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="BranchRef" type="BranchRef_T"/>
|
||||
<xs:complexType name="BranchRef_T">
|
||||
<xs:attribute name="Number" type="xs:int" use="required"/>
|
||||
<xs:attribute name="In" type="xs:int"/>
|
||||
<xs:attribute name="Out" type="xs:int"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Connection" type="Connection_T"/>
|
||||
<xs:complexType name="Connection_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="NodeFrom"/>
|
||||
<xs:element ref="NodeTo"/>
|
||||
<xs:element ref="LinkType"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="EndConnection"/>
|
||||
<xs:element name="Graph" type="Graph_T"/>
|
||||
<xs:complexType name="AlarmsSettings_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="AlarmSupervisionCategories"/>
|
||||
<xs:element ref="AlarmInterlockCategory"/>
|
||||
<xs:element ref="AlarmSubcategory1Interlock"/>
|
||||
<xs:element ref="AlarmSubcategory2Interlock"/>
|
||||
<xs:element ref="AlarmCategorySupervision"/>
|
||||
<xs:element ref="AlarmSubcategory1Supervision"/>
|
||||
<xs:element ref="AlarmSubcategory2Supervision"/>
|
||||
<xs:element ref="AlarmWarningCategory"/>
|
||||
<xs:element ref="AlarmSubcategory1Warning"/>
|
||||
<xs:element ref="AlarmSubcategory2Warning"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="AlarmsSettings" type="AlarmsSettings_T"/>
|
||||
<xs:complexType name="Graph_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="PreOperations"/>
|
||||
<xs:element ref="Sequence" maxOccurs="unbounded"/>
|
||||
<xs:element ref="PostOperations"/>
|
||||
<xs:element ref="AlarmsSettings"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="IdentRef" type="IdentRef_T"/>
|
||||
<xs:complexType name="IdentRef_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Comment" minOccurs="0"/>
|
||||
<xs:element ref="ViewInfo" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="PartAttribute_G"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Interlock" type="AlarmSupportingLanguageModule_T"/>
|
||||
<xs:element name="Interlocks" type="Interlocks_T"/>
|
||||
<xs:complexType name="Interlocks_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Interlock"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Link_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Direct"/>
|
||||
<xs:enumeration value="Jump"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="Node_T">
|
||||
<xs:choice>
|
||||
<xs:element ref="StepRef"/>
|
||||
<xs:element ref="TransitionRef"/>
|
||||
<xs:element ref="BranchRef"/>
|
||||
<xs:element ref="EndConnection"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
<xs:element name="NodeFrom" type="Node_T"/>
|
||||
<xs:element name="NodeTo" type="Node_T"/>
|
||||
<xs:element name="LinkType" type="Link_TE"/>
|
||||
<xs:element name="PermanentOperation" type="PermanentOperation_T"/>
|
||||
<xs:complexType name="PermanentOperation_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Title" minOccurs="0"/>
|
||||
<xs:element ref="FlgNet" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="ProgrammingLanguage" type="ProgrammingLanguage_TE" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PermanentOperations_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Title" minOccurs="0"/>
|
||||
<xs:element ref="Comment" minOccurs="0"/>
|
||||
<xs:element ref="PermanentOperation" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="PostOperations" type="PermanentOperations_T"/>
|
||||
<xs:element name="PreOperations" type="PermanentOperations_T"/>
|
||||
<xs:simpleType name="ProgrammingContext_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Plain"/>
|
||||
<xs:enumeration value="GraphTransition"/>
|
||||
<xs:enumeration value="GraphSupervision"/>
|
||||
<xs:enumeration value="GraphInterlock"/>
|
||||
<xs:enumeration value="GraphActions"/>
|
||||
<xs:enumeration value="PreOperation"/>
|
||||
<xs:enumeration value="PostOperation"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ProgrammingLanguage_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="STL"/>
|
||||
<xs:enumeration value="FBD"/>
|
||||
<xs:enumeration value="LAD"/>
|
||||
<xs:enumeration value="FBD_IEC"/>
|
||||
<xs:enumeration value="LAD_IEC"/>
|
||||
<xs:enumeration value="GRAPH"/>
|
||||
<xs:enumeration value="DB"/>
|
||||
<xs:enumeration value="SDB"/>
|
||||
<xs:enumeration value="DB_CPU"/>
|
||||
<xs:enumeration value="FB_IDB"/>
|
||||
<xs:enumeration value="SFB_IDB"/>
|
||||
<xs:enumeration value="DT_DB"/>
|
||||
<xs:enumeration value="SCL"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Sequence" type="Sequence_T"/>
|
||||
<xs:complexType name="Sequence_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Title" minOccurs="0"/>
|
||||
<xs:element ref="Comment" minOccurs="0"/>
|
||||
<xs:element ref="Steps"/>
|
||||
<xs:element ref="Transitions"/>
|
||||
<xs:element ref="Branches"/>
|
||||
<xs:element ref="Connections"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Step">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="Step_T"/>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="Step_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="StepName" minOccurs="0"/>
|
||||
<xs:element ref="Comment" minOccurs="0"/>
|
||||
<xs:element ref="Actions"/>
|
||||
<xs:element ref="Supervisions"/>
|
||||
<xs:element ref="Interlocks"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="IsMissing" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="Number" type="xs:int" use="required"/>
|
||||
<xs:attribute name="Init" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="Name" use="required"/>
|
||||
<xs:attribute name="MaximumStepTime" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="WarningTime" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="StepRef" type="StepRef_T"/>
|
||||
<xs:complexType name="StepRef_T">
|
||||
<xs:attribute name="Number" type="xs:int" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Steps" type="Steps_T"/>
|
||||
<xs:complexType name="Steps_T">
|
||||
<xs:sequence maxOccurs="unbounded">
|
||||
<xs:element ref="Step"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Connections" type="Connections_T"/>
|
||||
<xs:complexType name="Connections_T">
|
||||
<xs:sequence maxOccurs="unbounded">
|
||||
<xs:element ref="Connection"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Supervision" type="AlarmSupportingLanguageModule_T"/>
|
||||
<xs:element name="Supervisions" type="Supervisions_T"/>
|
||||
<xs:complexType name="Supervisions_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Supervision"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Title" type="Comment_T"/>
|
||||
<xs:complexType name="Transition_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="TransitionName" minOccurs="0"/>
|
||||
<xs:element ref="Comment" minOccurs="0"/>
|
||||
<xs:element ref="FlgNet"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="IsMissing" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="Name" use="required"/>
|
||||
<xs:attribute name="Number" type="xs:int" use="required"/>
|
||||
<xs:attribute name="ProgrammingLanguage" type="ProgrammingLanguage_TE" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="TransitionRef" type="TransitionRef_T"/>
|
||||
<xs:complexType name="TransitionRef_T">
|
||||
<xs:attribute name="Number" type="xs:int" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Transitions" type="Transitions_T"/>
|
||||
<xs:complexType name="Transitions_T">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Transition"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="Action" type="Action_T"/>
|
||||
<xs:element name="Transition" type="Transition_T"/>
|
||||
<xs:element name="Branch" type="Branch_T"/>
|
||||
<xs:element name="AlarmSupervisionCategories" type="AlarmSupervisionCategories_T"/>
|
||||
<xs:complexType name="AlarmSupervisionCategories_T">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="AlarmSupervisionCategory"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="AlarmSupervisionCategory" type="AlarmSupervisionCategory_T"/>
|
||||
<xs:complexType name="AlarmSupervisionCategory_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Token" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Enabler token</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Id" type="xs:unsignedShort" use="required"/>
|
||||
<xs:attribute name="DisplayClass" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:unsignedShort">
|
||||
<xs:minInclusive value="0"/>
|
||||
<xs:maxInclusive value="16"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
<xs:element name="AlarmInterlockCategory" type="AlarmCategory_T"/>
|
||||
<xs:element name="AlarmSubcategory1Interlock" type="AlarmSubcategory_T"/>
|
||||
<xs:element name="AlarmSubcategory2Interlock" type="AlarmSubcategory_T"/>
|
||||
<xs:element name="AlarmCategorySupervision" type="AlarmCategory_T"/>
|
||||
<xs:element name="AlarmSubcategory1Supervision" type="AlarmSubcategory_T"/>
|
||||
<xs:element name="AlarmSubcategory2Supervision" type="AlarmSubcategory_T"/>
|
||||
<xs:element name="AlarmWarningCategory" type="AlarmCategory_T"/>
|
||||
<xs:element name="AlarmSubcategory1Warning" type="AlarmSubcategory_T"/>
|
||||
<xs:element name="AlarmSubcategory2Warning" type="AlarmSubcategory_T"/>
|
||||
<xs:complexType name="AlarmCategory_T">
|
||||
<xs:attribute name="Id" type="xs:unsignedShort" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="TransitionName" type="TransitionName_T"/>
|
||||
<xs:complexType name="TransitionName_T">
|
||||
<xs:sequence>
|
||||
<xs:annotation>
|
||||
<xs:documentation>For translated transiton names</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:element ref="MultiLanguageText" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="StepName" type="StepName_T"/>
|
||||
<xs:complexType name="StepName_T">
|
||||
<xs:sequence>
|
||||
<xs:annotation>
|
||||
<xs:documentation>For translated step names</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:element ref="MultiLanguageText" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="AlarmSubcategory_T">
|
||||
<xs:attribute name="Id" type="xs:unsignedShort" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- <xs:include schemaLocation="SW.Common_v3.xsd"/>-->
|
||||
<xs:element name="SupervisionFB">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="StateStruct">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Number" type="xs:int"/>
|
||||
<xs:element name="Multiinstance">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="BlockTypeSupervisionNumber" type="xs:int"/>
|
||||
<xs:element name="BlockInstSupervisionGroups" type="BlockInstSupervisionGroupsType"/>
|
||||
<xs:element name="BlockInstSupervisionGroup">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="Multiinstance" minOccurs="0"/>
|
||||
<xs:element ref="BlockInstSupervision" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="BlockInstSupervision">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="Number"/>
|
||||
<xs:element ref="StateStruct"/>
|
||||
<xs:element ref="BlockTypeSupervisionNumber"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="BlockInstSupervisionGroupsType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="BlockInstSupervisionGroup" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,150 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.PlcBlocks.CompileUnitCommon_v4.xsd"/>
|
||||
<xs:element name="Powerrail" type="Powerrail_T"/>
|
||||
<xs:complexType name="Powerrail_T"/>
|
||||
<xs:element name="Openbranch" type="Openbranch_T"/>
|
||||
<xs:complexType name="Openbranch_T"/>
|
||||
<xs:element name="OpenCon" type="OpenCon_T"/>
|
||||
<xs:complexType name="OpenCon_T">
|
||||
<xs:attribute name="UId" type="xs:int" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Call" type="Call_T"/>
|
||||
<xs:complexType name="Call_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="CallInfo"/>
|
||||
<xs:group ref="PartSequence_G"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="PartAttribute_G"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Equation_T">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="FlgNet" type="FlgNet_T"/>
|
||||
<xs:complexType name="FlgNet_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="Labels" minOccurs="0"/>
|
||||
<xs:element ref="Parts"/>
|
||||
<xs:element ref="Wires" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="GateName_TE">
|
||||
<xs:restriction base="xs:string"/>
|
||||
</xs:simpleType>
|
||||
<xs:element name="IdentCon" type="IdentCon_T"/>
|
||||
<xs:complexType name="IdentCon_T">
|
||||
<xs:attribute name="UId" type="xs:int" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Invisible" type="Invisible_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The invisible pins of this part.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="Invisible_T">
|
||||
<xs:attribute name="Name" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The name of the invisible pin.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
<xs:element name="Labels" type="Labels_T"/>
|
||||
<xs:complexType name="Labels_T">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="LabelDeclaration"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Neg_T">
|
||||
<xs:attribute name="Name" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The name of the negated pin.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
<xs:element name="Negated" type="Neg_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The negated pins of this part.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:complexType name="AutomaticTyped_T">
|
||||
<xs:attribute name="Name" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The name of the automatic chosen template parameter. Not for InstructionRef</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
<xs:element name="AutomaticTyped" type="AutomaticTyped_T"/>
|
||||
<xs:element name="Part" type="Part_T"/>
|
||||
<xs:element name="Equation" type="Equation_T"/>
|
||||
<xs:complexType name="Part_T">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0">
|
||||
<xs:element ref="Equation" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The equation of this part. This is only used for the Calculate box.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element ref="Instance" minOccurs="0"/>
|
||||
</xs:choice>
|
||||
<xs:group ref="PartSequence_G"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="PartAttribute_G"/>
|
||||
<xs:attribute name="Name" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="SimaticName_TP">
|
||||
<xs:minLength value="1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Version" type="VersionString_TP"/>
|
||||
<xs:attribute name="DisabledENO" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
<xs:attributeGroup name="PartAttribute_G">
|
||||
<xs:attribute name="UId" type="xs:int" use="required"/>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="NameCon" type="NameCon_T"/>
|
||||
<xs:complexType name="NameCon_T">
|
||||
<xs:attribute name="UId" type="xs:int" use="required"/>
|
||||
<xs:attribute name="Name" type="PinName_TE" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Parts" type="Parts_T"/>
|
||||
<xs:complexType name="Parts_T">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="Access"/>
|
||||
<xs:element ref="Part"/>
|
||||
<xs:element ref="Call"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
<xs:group name="PartSequence_G">
|
||||
<xs:sequence>
|
||||
<xs:element ref="TemplateValue" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="AutomaticTyped" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="Invisible" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="Negated" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="Comment" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:group>
|
||||
<xs:simpleType name="PinName_TE">
|
||||
<xs:restriction base="xs:string"/>
|
||||
</xs:simpleType>
|
||||
<xs:element name="Wire" type="Wire_T"/>
|
||||
<xs:complexType name="Wire_T">
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element ref="Powerrail"/>
|
||||
<xs:element ref="NameCon"/>
|
||||
<xs:element ref="IdentCon"/>
|
||||
<xs:element ref="Openbranch"/>
|
||||
<xs:element ref="OpenCon"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="UId" type="xs:int" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:element name="Wires" type="Wires_T"/>
|
||||
<xs:complexType name="Wires_T">
|
||||
<xs:sequence maxOccurs="unbounded">
|
||||
<xs:element ref="Wire"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.PlcBlocks.Access_v4.xsd"/>
|
||||
<xs:element name="StructuredText" type="StructuredText_T"/>
|
||||
<xs:complexType name="StructuredText_T">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:choice>
|
||||
<xs:element ref="Access"/>
|
||||
<xs:element ref="Token"/>
|
||||
<xs:element ref="Parameter"/>
|
||||
<xs:element ref="Text"/>
|
||||
<xs:group ref="Comment_G"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,482 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.PlcBlocks.CompileUnitCommon_v4.xsd"/>
|
||||
<xs:element name="StlStatement" type="StlStatement_T"/>
|
||||
<xs:complexType name="StlStatement_T">
|
||||
<xs:sequence>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
<xs:element ref="LabelDeclaration" minOccurs="0"/>
|
||||
<xs:sequence>
|
||||
<xs:element ref="StlToken">
|
||||
<xs:annotation>
|
||||
<xs:documentation>missing for empty lines</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:element ref="Access" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="UId" type="xs:int">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not allowed in STL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
<xs:element name="StlToken" type="StlToken_T"/>
|
||||
<xs:complexType name="StlToken_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="IntegerAttribute" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>for NumBLs. NumBLs is informative</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:group ref="Comment_G" minOccurs="0"/>
|
||||
<xs:element ref="Token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>e.g 0 1 for NOP 0, NOP 1; STW for L STW or DILG for L DILG; only if separated by comment</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="UId" type="xs:int" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Not allowed in STL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Text" type="STL_TE" use="required"/>
|
||||
<!--<xs:attribute name="NumBLs" type="xs:int" default="0"/>-->
|
||||
</xs:complexType>
|
||||
<xs:element name="StatementList" type="StatementList_T"/>
|
||||
<xs:complexType name="StatementList_T">
|
||||
<xs:sequence>
|
||||
<xs:element ref="StlStatement" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="STL_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="A"/>
|
||||
<xs:enumeration value="AN"/>
|
||||
<xs:enumeration value="O"/>
|
||||
<xs:enumeration value="ON"/>
|
||||
<xs:enumeration value="X"/>
|
||||
<xs:enumeration value="XN"/>
|
||||
<xs:enumeration value="S"/>
|
||||
<xs:enumeration value="R"/>
|
||||
<xs:enumeration value="Assign"/>
|
||||
<xs:enumeration value="Rise"/>
|
||||
<xs:enumeration value="Fall"/>
|
||||
<xs:enumeration value="L"/>
|
||||
<xs:enumeration value="T"/>
|
||||
<xs:enumeration value="LAR1"/>
|
||||
<xs:enumeration value="LAR2"/>
|
||||
<xs:enumeration value="TAR1"/>
|
||||
<xs:enumeration value="TAR2"/>
|
||||
<xs:enumeration value="Extend">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SE, SV</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="Free"/>
|
||||
<xs:enumeration value="LC"/>
|
||||
<xs:enumeration value="OffDelay">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SF, SA</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="Retentive">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SS</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="OnDelay">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SD, SE</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="Pulse">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SP, SI</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="CD"/>
|
||||
<xs:enumeration value="CU"/>
|
||||
<xs:enumeration value="CALL"/>
|
||||
<xs:enumeration value="CC"/>
|
||||
<xs:enumeration value="UC"/>
|
||||
<xs:enumeration value="OPEN_DB">
|
||||
<xs:annotation>
|
||||
<xs:documentation>AUF</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="OPEN_DI">
|
||||
<xs:annotation>
|
||||
<xs:documentation>AUF DI</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="LT_I"/>
|
||||
<xs:enumeration value="LT_R"/>
|
||||
<xs:enumeration value="LT_D"/>
|
||||
<xs:enumeration value="LE_I"/>
|
||||
<xs:enumeration value="LE_R"/>
|
||||
<xs:enumeration value="LE_D"/>
|
||||
<xs:enumeration value="EQ_I"/>
|
||||
<xs:enumeration value="EQ_R"/>
|
||||
<xs:enumeration value="EQ_D"/>
|
||||
<xs:enumeration value="GE_I"/>
|
||||
<xs:enumeration value="GE_R"/>
|
||||
<xs:enumeration value="GE_D"/>
|
||||
<xs:enumeration value="GT_I"/>
|
||||
<xs:enumeration value="GT_R"/>
|
||||
<xs:enumeration value="GT_D"/>
|
||||
<xs:enumeration value="NE_I"/>
|
||||
<xs:enumeration value="NE_R"/>
|
||||
<xs:enumeration value="NE_D"/>
|
||||
<xs:enumeration value="JU">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPA</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JC">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPB</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JO">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPO</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JZ">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPZ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JP">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPP</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JM">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPM</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JN">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPN</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JCN">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPBN</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JCB">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPBB</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JNB">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPBNB</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JBI">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPBI</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JNBI">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPBNI</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JOS">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPS</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JUN">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPU</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JMZ">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPMZ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="JPZ">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SPZ</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="LOOP"/>
|
||||
<xs:enumeration value="JL"/>
|
||||
<xs:enumeration value="ADD"/>
|
||||
<xs:enumeration value="SLD"/>
|
||||
<xs:enumeration value="SLW"/>
|
||||
<xs:enumeration value="SRD"/>
|
||||
<xs:enumeration value="SRW"/>
|
||||
<xs:enumeration value="SRSD">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SSD, SVD</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="SRSW">
|
||||
<xs:annotation>
|
||||
<xs:documentation>SSW, SVW</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="RLD"/>
|
||||
<xs:enumeration value="RRD"/>
|
||||
<xs:enumeration value="BLD"/>
|
||||
<xs:enumeration value="ADDAR1"/>
|
||||
<xs:enumeration value="ADDAR2"/>
|
||||
<xs:enumeration value="INC"/>
|
||||
<xs:enumeration value="DEC"/>
|
||||
<xs:enumeration value="AW"/>
|
||||
<xs:enumeration value="OW"/>
|
||||
<xs:enumeration value="XW"/>
|
||||
<xs:enumeration value="AD"/>
|
||||
<xs:enumeration value="OD"/>
|
||||
<xs:enumeration value="XD"/>
|
||||
<xs:enumeration value="A_BRACK"/>
|
||||
<xs:enumeration value="AN_BRACK"/>
|
||||
<xs:enumeration value="O_BRACK"/>
|
||||
<xs:enumeration value="ON_BRACK"/>
|
||||
<xs:enumeration value="X_BRACK"/>
|
||||
<xs:enumeration value="XN_BRACK"/>
|
||||
<xs:enumeration value="INV_I">
|
||||
<xs:annotation>
|
||||
<xs:documentation>KEW, INV_F</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="NEG_I">
|
||||
<xs:annotation>
|
||||
<xs:documentation>KZW, NEG_F</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="INV_D">
|
||||
<xs:annotation>
|
||||
<xs:documentation>KED</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="NEG_D">
|
||||
<xs:annotation>
|
||||
<xs:documentation>KZD</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="NEG_R">
|
||||
<xs:annotation>
|
||||
<xs:documentation>NEG_G, ND</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="ABS_R">
|
||||
<xs:annotation>
|
||||
<xs:documentation>ABS_G</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="SQRT"/>
|
||||
<xs:enumeration value="SQR"/>
|
||||
<xs:enumeration value="LN"/>
|
||||
<xs:enumeration value="EXP"/>
|
||||
<xs:enumeration value="SIN"/>
|
||||
<xs:enumeration value="ASIN"/>
|
||||
<xs:enumeration value="COS"/>
|
||||
<xs:enumeration value="ACOS"/>
|
||||
<xs:enumeration value="TAN"/>
|
||||
<xs:enumeration value="ATAN"/>
|
||||
<xs:enumeration value="RLDA"/>
|
||||
<xs:enumeration value="RRDA"/>
|
||||
<xs:enumeration value="BTI">
|
||||
<xs:annotation>
|
||||
<xs:documentation>DEF</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="ITB">
|
||||
<xs:annotation>
|
||||
<xs:documentation>DUF</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="BTD">
|
||||
<xs:annotation>
|
||||
<xs:documentation>DED</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="DTB">
|
||||
<xs:annotation>
|
||||
<xs:documentation>DUD</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="DTR">
|
||||
<xs:annotation>
|
||||
<xs:documentation>FDG</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="RND">
|
||||
<xs:annotation>
|
||||
<xs:documentation>GFDN</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="RND_M">
|
||||
<xs:annotation>
|
||||
<xs:documentation>GFDM</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="RND_P">
|
||||
<xs:annotation>
|
||||
<xs:documentation>GFDP</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="TRUNC"/>
|
||||
<xs:enumeration value="ITD">
|
||||
<xs:annotation>
|
||||
<xs:documentation>FD</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="CAW">
|
||||
<xs:annotation>
|
||||
<xs:documentation>TAW</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="CAD">
|
||||
<xs:annotation>
|
||||
<xs:documentation>TAD</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="TAR1_ACCU1"/>
|
||||
<xs:enumeration value="TAR2_ACCU1"/>
|
||||
<xs:enumeration value="ADD_I">
|
||||
<xs:annotation>
|
||||
<xs:documentation>+F</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="SUB_I">
|
||||
<xs:annotation>
|
||||
<xs:documentation>-F</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="MUL_I">
|
||||
<xs:annotation>
|
||||
<xs:documentation>xF</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="DIV_I">
|
||||
<xs:annotation>
|
||||
<xs:documentation>:F</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="ADD_D">
|
||||
<xs:annotation>
|
||||
<xs:documentation>+D</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="SUB_D">
|
||||
<xs:annotation>
|
||||
<xs:documentation>-D</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="MUL_D">
|
||||
<xs:annotation>
|
||||
<xs:documentation>xD</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="DIV_D">
|
||||
<xs:annotation>
|
||||
<xs:documentation>:D</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="MOD_D"/>
|
||||
<xs:enumeration value="L_DBLG"/>
|
||||
<xs:enumeration value="L_DILG"/>
|
||||
<xs:enumeration value="L_DBNO"/>
|
||||
<xs:enumeration value="L_DINO"/>
|
||||
<xs:enumeration value="ADD_R">
|
||||
<xs:annotation>
|
||||
<xs:documentation>+G</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="SUB_R">
|
||||
<xs:annotation>
|
||||
<xs:documentation>-G</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="MUL_R">
|
||||
<xs:annotation>
|
||||
<xs:documentation>xG</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="DIV_R">
|
||||
<xs:annotation>
|
||||
<xs:documentation>:G</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="CAC">
|
||||
<xs:annotation>
|
||||
<xs:documentation>TAK</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="LEAVE"/>
|
||||
<xs:enumeration value="PUSH"/>
|
||||
<xs:enumeration value="POP"/>
|
||||
<xs:enumeration value="SET"/>
|
||||
<xs:enumeration value="NEG"/>
|
||||
<xs:enumeration value="CLR"/>
|
||||
<xs:enumeration value="BEC">
|
||||
<xs:annotation>
|
||||
<xs:documentation>BEB</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="BRACKET">
|
||||
<xs:annotation>
|
||||
<xs:documentation>)</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="SAVE"/>
|
||||
<xs:enumeration value="NOP_0"/>
|
||||
<xs:enumeration value="NOP_1"/>
|
||||
<xs:enumeration value="MCR_BRACK">
|
||||
<xs:annotation>
|
||||
<xs:documentation>MCR(</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="BRACK_MCR">
|
||||
<xs:annotation>
|
||||
<xs:documentation>MCR)</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="MCRA"/>
|
||||
<xs:enumeration value="MCRD"/>
|
||||
<xs:enumeration value="ENT"/>
|
||||
<xs:enumeration value="LAR1_ACCU1"/>
|
||||
<xs:enumeration value="LAR1_AR2"/>
|
||||
<xs:enumeration value="LAR2_ACCU1"/>
|
||||
<xs:enumeration value="TAR1_AR2"/>
|
||||
<xs:enumeration value="CAR">
|
||||
<xs:annotation>
|
||||
<xs:documentation>TAR</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="CDB">
|
||||
<xs:annotation>
|
||||
<xs:documentation>TDB</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="COMMENT"/>
|
||||
<xs:enumeration value="EMPTY_LINE"/>
|
||||
<xs:enumeration value="PSEUDO"/>
|
||||
<xs:enumeration value="MOVE"/>
|
||||
<xs:enumeration value="MOVE_BLOCK"/>
|
||||
<xs:enumeration value="BE">
|
||||
<xs:annotation>
|
||||
<xs:documentation>BEA</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:enumeration>
|
||||
<xs:enumeration value="BEU"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,154 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="SW.Common_v3.xsd"/>
|
||||
<xs:element name="Type">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Action"/>
|
||||
<xs:enumeration value="Interlock"/>
|
||||
<xs:enumeration value="Operand"/>
|
||||
<xs:enumeration value="Position"/>
|
||||
<xs:enumeration value="Reaction"/>
|
||||
<xs:enumeration value="MessageText"/>
|
||||
<xs:enumeration value="MessageError"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="TriggeringStatus" type="xs:boolean"/>
|
||||
<xs:element name="SupervisedStatus" type="xs:boolean"/>
|
||||
<xs:element name="SupervisedOperand">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="SubCategory2Number" type="xs:int"/>
|
||||
<xs:element name="SubCategory1Number" type="xs:int"/>
|
||||
<xs:element name="Number" type="xs:int"/>
|
||||
<xs:element name="DelayOperand">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Conditions">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="Condition" maxOccurs="3"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ConditionOperand">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Number" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:int">
|
||||
<xs:enumeration value="1"/>
|
||||
<xs:enumeration value="2"/>
|
||||
<xs:enumeration value="3"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Condition">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="ConditionOperand"/>
|
||||
<xs:element ref="TriggeringStatus"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="CategoryNumber">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:int">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="8"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="BlockTypeSupervisions">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="BlockTypeSupervisionsType"/>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="BlockTypeSupervision">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="SupervisedOperand"/>
|
||||
<xs:element ref="SupervisedStatus"/>
|
||||
<xs:element ref="DelayOperand" minOccurs="0"/>
|
||||
<xs:element ref="Conditions" minOccurs="0"/>
|
||||
<xs:element ref="CategoryNumber"/>
|
||||
<xs:element ref="SubCategory1Number" minOccurs="0"/>
|
||||
<xs:element ref="SubCategory2Number" minOccurs="0"/>
|
||||
<xs:element ref="SpecificField" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Number" type="xs:int" use="required"/>
|
||||
<xs:attribute name="Type" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Action"/>
|
||||
<xs:enumeration value="Interlock"/>
|
||||
<xs:enumeration value="Operand"/>
|
||||
<xs:enumeration value="Position"/>
|
||||
<xs:enumeration value="Reaction"/>
|
||||
<xs:enumeration value="MessageText"/>
|
||||
<xs:enumeration value="MessageError"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="AssociatedValues">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="AssociatedValue" maxOccurs="3"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="AssociatedValue">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="AssociatedValueOperand" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="SpecificFieldText">
|
||||
<xs:complexType>
|
||||
<xs:sequence maxOccurs="unbounded">
|
||||
<xs:element ref="MultiLanguageText"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="SpecificField">
|
||||
<xs:complexType>
|
||||
<xs:sequence minOccurs="0">
|
||||
<xs:element ref="AssociatedValues" minOccurs="0"/>
|
||||
<xs:element ref="SpecificFieldText" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="BlockTypeSupervisionsType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="BlockTypeSupervision" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:element name="AssociatedValueOperand">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Number" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:int">
|
||||
<xs:enumeration value="1"/>
|
||||
<xs:enumeration value="2"/>
|
||||
<xs:enumeration value="3"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Name" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
|
@ -0,0 +1,132 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.siemens.com/automation/Openness/SW/Motion/Axis/v1"
|
||||
xmlns:tns="http://www.siemens.com/automation/Openness/SW/Motion/Axis/v1"
|
||||
elementFormDefault="qualified">
|
||||
<!-- Root element AdditionalData-->
|
||||
<xs:element name="AdditionalData" type="tns:AdditionalData_T"/>
|
||||
|
||||
<!-- Complex type AdditionalData_T-->
|
||||
<xs:complexType name="AdditionalData_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes additional data, such as Connections, for Axis and ExternalEncoder TOs.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Connection" type="tns:Connection_T" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="SynchronousAxisMasterValues" type="tns:SynchronousAxisMasterValues_T" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Complex type Connection_T-->
|
||||
<xs:complexType name="Connection_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a connection of a TO interface.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="Interface" type="tns:Interface_TE" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the Interface of the TO that is connected.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="InputAddress" type="xs:nonNegativeInteger" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Input bit address.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="OutputAddress" type="xs:nonNegativeInteger" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Output bit address.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="ConnectOption" type="tns:ConnectOption_TE" use="optional" default="Default">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Connect option used when the connection has been created.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SensorIndexInActorTelegram" type="xs:nonNegativeInteger" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Index of sensor in actor telegram if connected to same telegram.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="PathToDBMember" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Path to a DB member.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="OutputTag" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Name of a connected tag for analog connection.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Enumeration type Interface_TE-->
|
||||
<xs:simpleType name="Interface_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Actor"/>
|
||||
<xs:enumeration value="Sensor"/>
|
||||
<xs:enumeration value="Sensor[1]"/>
|
||||
<xs:enumeration value="Sensor[2]"/>
|
||||
<xs:enumeration value="Sensor[3]"/>
|
||||
<xs:enumeration value="Sensor[4]"/>
|
||||
<xs:enumeration value="Torque"/>
|
||||
<xs:enumeration value="OutputCam"/>
|
||||
<xs:enumeration value="MeasuringInput"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<!-- Enumeration type ConnectOption_TE-->
|
||||
<xs:simpleType name="ConnectOption_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Default"/>
|
||||
<xs:enumeration value="AllowAllModules"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<!-- Complex type SynchronousAxisMasterValues_T-->
|
||||
<xs:complexType name="SynchronousAxisMasterValues_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Contains a list of master values for TO_SynchronousAxis.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="SetPointCoupling" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a master value TO that is coupled via set points.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="ActualValueCoupling" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a master value TO that is coupled via actual values.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="DelayedCoupling" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a master value TO that is coupled via delayed values.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="LeadingAxisProxy" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a master value TO of type LeadingAxisProxy.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Complex type TechnologicalObjectReference_T-->
|
||||
<xs:complexType name="TechnologicalObjectReference_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="Ref" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the name of the referenced Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Type" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the type of the referenced Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2019. All rights reserved. -->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.siemens.com/automation/Openness/SW/Motion/Kinematics/v1"
|
||||
xmlns:tns="http://www.siemens.com/automation/Openness/SW/Motion/Kinematics/v1"
|
||||
elementFormDefault="qualified">
|
||||
<!-- Root element AdditionalData-->
|
||||
<xs:element name="AdditionalData" type="tns:AdditionalData_T"/>
|
||||
|
||||
<!-- Complex type AdditionalData_T-->
|
||||
<xs:complexType name="AdditionalData_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes additional data, such as connected axes, for Kinematics TOs.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="KinematicsAxis" type="tns:TechnologicalObjectReferenceWithIndex_T" minOccurs="0" maxOccurs="4"/>
|
||||
<xs:element name="ConveyorTrackingLeadingValues" type="tns:ConveyorTrackingLeadingValues_T" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Complex type TechnologicalObjectReferenceWithIndex_T-->
|
||||
<xs:complexType name="TechnologicalObjectReferenceWithIndex_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="Index" type="tns:Integer1to4_T" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the name of the referenced Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Ref" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the name of the referenced Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Type" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the type of the referenced Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Simple type Integer1to4_T-->
|
||||
<xs:simpleType name="Integer1to4_T">
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:minInclusive value="1"/>
|
||||
<xs:maxInclusive value="4"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<!-- Complex type ConveyorTrackingLeadingValues_T-->
|
||||
<xs:complexType name="ConveyorTrackingLeadingValues_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Contains a list of leading values for conveyor tracking.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="SetPointCoupling" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a leading value TO that is coupled via set points.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="ActualValueCoupling" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a leading value TO that is coupled via actual values.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="DelayedCoupling" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a leading value TO that is coupled via delayed values.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="LeadingAxisProxy" type="tns:TechnologicalObjectReference_T" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a leading value TO of type LeadingAxisProxy.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Complex type TechnologicalObjectReference_T-->
|
||||
<xs:complexType name="TechnologicalObjectReference_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a reference to a Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="Ref" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the name of the referenced Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Type" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the type of the referenced Technological Object.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2018. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.siemens.com/automation/Openness/SW/Motion/MeasuringInput/v1"
|
||||
xmlns:tns="http://www.siemens.com/automation/Openness/SW/Motion/MeasuringInput/v1"
|
||||
elementFormDefault="qualified">
|
||||
<!-- Root element AdditionalData-->
|
||||
<xs:element name="AdditionalData" type="tns:AdditionalData_T"/>
|
||||
|
||||
<!-- Complex type AdditionalData_T-->
|
||||
<xs:complexType name="AdditionalData_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes additional data, such as Connections, for MeasuringInput TOs.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Connection" type="tns:Connection_T" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Complex type Connection_T-->
|
||||
<xs:complexType name="Connection_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a connection of a TO interface.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="Interface" type="tns:Interface_TE" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the Interface of the TO that is connected.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="InputAddress" type="xs:nonNegativeInteger" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Input bit address.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Enumeration type Interface_TE-->
|
||||
<xs:simpleType name="Interface_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="MeasuringInput"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
</xs:schema>
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2018. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.siemens.com/automation/Openness/SW/Motion/OutputCam/v1"
|
||||
xmlns:tns="http://www.siemens.com/automation/Openness/SW/Motion/OutputCam/v1"
|
||||
elementFormDefault="qualified">
|
||||
<!-- Root element AdditionalData-->
|
||||
<xs:element name="AdditionalData" type="tns:AdditionalData_T"/>
|
||||
|
||||
<!-- Complex type AdditionalData_T-->
|
||||
<xs:complexType name="AdditionalData_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes additional data, such as Connections, for OutputCam and CamTrack TOs.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Connection" type="tns:Connection_T" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Complex type Connection_T-->
|
||||
<xs:complexType name="Connection_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a connection of a TO interface.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="Interface" type="tns:Interface_TE" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies the Interface of the TO that is connected.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="OutputAddress" type="xs:nonNegativeInteger" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Output bit address.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="OutputTag" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Name of a connected tag.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Enumeration type Interface_TE-->
|
||||
<xs:simpleType name="Interface_TE">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="OutputCam"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2018. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.siemens.com/automation/Openness/SW/Parameters/v1"
|
||||
xmlns:tns="http://www.siemens.com/automation/Openness/SW/Parameters/v1"
|
||||
elementFormDefault="qualified">
|
||||
<!-- Root element Parameters-->
|
||||
<xs:element name="Parameters" type="tns:Parameters_T"/>
|
||||
|
||||
<!-- Complex type Parameters_T-->
|
||||
<xs:complexType name="Parameters_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a list of parameters.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:element name="Parameter" type="tns:Parameter_T" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:any namespace="##other" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Complex type Parameter_T-->
|
||||
<xs:complexType name="Parameter_T">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Describes a single parameter, having Name and Value. If the Value is missing, the default value of the Parameter is used.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="Name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Name of the Parameter</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Value" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Value of the Parameter</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
|
@ -0,0 +1,345 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright © Siemens AG 2008-2018. All rights reserved. -->
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.siemens.com/automation/Openness/SW/Motion/Cam/v1"
|
||||
xmlns:cam="http://www.siemens.com/automation/Openness/SW/Motion/Cam/v1"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<!-- Global types -->
|
||||
|
||||
<xs:simpleType name="ProfileContinuity">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Position"/>
|
||||
<xs:enumeration value="Velocity"/>
|
||||
<xs:enumeration value="Acceleration"/>
|
||||
<xs:enumeration value="Jerk"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="ElementContinuity">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="AsProfile"/>
|
||||
<xs:enumeration value="Position"/>
|
||||
<xs:enumeration value="Velocity"/>
|
||||
<xs:enumeration value="Acceleration"/>
|
||||
<xs:enumeration value="Jerk"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="ProfileOptimizationGoal">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="None"/>
|
||||
<xs:enumeration value="Velocity"/>
|
||||
<xs:enumeration value ="Acceleration"/>
|
||||
<xs:enumeration value ="Jerk"/>
|
||||
<xs:enumeration value ="DynamicMoment"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="ElementOptimizationGoal">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="AsProfile"/>
|
||||
<xs:enumeration value="None"/>
|
||||
<xs:enumeration value="Velocity"/>
|
||||
<xs:enumeration value="Acceleration"/>
|
||||
<xs:enumeration value="Jerk"/>
|
||||
<xs:enumeration value="DynamicMoment"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="ValueMode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Relative"/>
|
||||
<xs:enumeration value="Absolute"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="ProfileInterpolationMode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Linear"/>
|
||||
<xs:enumeration value="CubicSpline"/>
|
||||
<xs:enumeration value="BezierSpline"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="BoundaryConditions">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="NoConstraint"/>
|
||||
<xs:enumeration value="FirstDerivative"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="DefinitionRange">
|
||||
<xs:attribute name="Start" type="xs:float"/>
|
||||
<xs:attribute name="End" type="xs:float"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="TrigonometricValues">
|
||||
<xs:attribute name="Amplitude" type="xs:float" default="1" />
|
||||
|
||||
<!-- two of four are required and at least StartPhase or EndPhase is required -->
|
||||
<xs:attribute name="StartPhase" type="xs:float" default="0" />
|
||||
<xs:attribute name="EndPhase" type="xs:float" default="6.2831853071795862" />
|
||||
<xs:attribute name="Frequency" type="xs:float" default="1" />
|
||||
<xs:attribute name="PeriodLength" type="xs:float" default="1" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="SegmentBase">
|
||||
<xs:attribute name="StartX" type="xs:float" use="required" />
|
||||
<xs:attribute name="EndX" type="xs:float" use="required" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="PointGroupApproximationMode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="PointApproximation" />
|
||||
<xs:enumeration value="SegmentApproximation" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="PointGroupInterpolationMode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="CubicSpline" />
|
||||
<xs:enumeration value="BezierSpline" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<!-- Due to multiple usage, we place that element type explicitly here -->
|
||||
<xs:complexType name="PointElementType">
|
||||
<xs:attribute name="X" type="xs:float" use="required" />
|
||||
<xs:attribute name="Y" type="xs:float" use="required" />
|
||||
<xs:attribute name="Velocity" type="xs:float" />
|
||||
<xs:attribute name="Acceleration" type="xs:float" />
|
||||
<xs:attribute name="Jerk" type="xs:float" />
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Begin of our actual nodes -->
|
||||
<xs:element name="ProfileData">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
|
||||
<xs:element name="GeneralConfiguration" minOccurs="1" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<!-- Requires start < end validity - default is [0;360] -->
|
||||
<xs:element name="DesignLeadingRange" type="cam:DefinitionRange" minOccurs="1" maxOccurs="1" />
|
||||
<!-- Requires start < end validity - default is [-1;1] -->
|
||||
<xs:element name="DesignFollowingRange" type="cam:DefinitionRange" minOccurs="1" maxOccurs="1" />
|
||||
</xs:sequence>
|
||||
|
||||
<!-- Attributes -->
|
||||
<xs:attribute name="StandardContinuity" type="cam:ProfileContinuity" default="Acceleration" />
|
||||
<xs:attribute name="StandardOptimizationGoal" type="cam:ProfileOptimizationGoal" default="None" />
|
||||
<xs:attribute name="InterpolationMode" type="cam:ProfileInterpolationMode" default="CubicSpline" />
|
||||
<xs:attribute name="BoundaryConditions" type="cam:BoundaryConditions" default="NoConstraint" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<!-- The node of listed elements -->
|
||||
<xs:element name="Elements" minOccurs="1" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
|
||||
<xs:element name="Point" type="cam:PointElementType" />
|
||||
|
||||
<xs:element name="Line">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="cam:SegmentBase">
|
||||
<!-- Two out of three are required here -->
|
||||
<xs:attribute name="StartY" type="xs:float" />
|
||||
<xs:attribute name="EndY" type="xs:float" />
|
||||
<xs:attribute name="Gradient" type="xs:float" />
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="Polynomial">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="cam:SegmentBase">
|
||||
<xs:sequence>
|
||||
|
||||
<!-- With or without trigonometric portion ? If node doesn't exist, we simply use a non-trig. polynomial -->
|
||||
<!-- 2 out of 4 : startPhase, endPhase, frequency, periodLength -->
|
||||
<xs:element name="TrigonometricValues" type="cam:TrigonometricValues" minOccurs="0" maxOccurs="1" />
|
||||
|
||||
<!-- For V3, one of these nodes is required. -->
|
||||
|
||||
<xs:choice>
|
||||
<xs:element name="Coefficients" >
|
||||
<xs:complexType>
|
||||
<xs:attribute name="C0" type="xs:float" default="0" />
|
||||
<xs:attribute name="C1" type="xs:float" default="0" />
|
||||
<xs:attribute name="C2" type="xs:float" default="0" />
|
||||
<xs:attribute name="C3" type="xs:float" default="0" />
|
||||
<xs:attribute name="C4" type="xs:float" default="0" />
|
||||
<xs:attribute name="C5" type="xs:float" default="0" />
|
||||
<xs:attribute name="C6" type="xs:float" default="0" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="Constraints" >
|
||||
<xs:complexType>
|
||||
<xs:attribute name="LeftValue" type="xs:float" />
|
||||
<xs:attribute name="RightValue" type="xs:float" />
|
||||
<xs:attribute name="LeftVelocity" type="xs:float" />
|
||||
<xs:attribute name="RightVelocity" type="xs:float" />
|
||||
<xs:attribute name="LeftAcceleration" type="xs:float" />
|
||||
<xs:attribute name="RightAcceleration" type="xs:float" />
|
||||
|
||||
<!-- For V3, only one of these three parameters is allowed and lambda is always assumed to be absolute there. -->
|
||||
<xs:attribute name="LeftJerk" type="xs:float" />
|
||||
<xs:attribute name="RightJerk" type="xs:float" />
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="VDITransition">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="cam:SegmentBase">
|
||||
|
||||
<!-- The VDI-rules we know so far -->
|
||||
<!-- If a VDI-rule occurs, the transition is handled as a VDI transition -->
|
||||
<!-- For V3, lambda is always expected to be absolute -> mode is ignored there. -->
|
||||
<xs:choice minOccurs="1" maxOccurs="1">
|
||||
<xs:element name="DoubleHarmonicTransition" />
|
||||
<xs:element name="InclinedSine">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Linear" />
|
||||
<xs:element name="HarmonicCombination">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ModifiedAccelerationTrapezoid">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ModifiedSine">
|
||||
<xs:complexType>
|
||||
<!-- Choose one of three -->
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="Ca" type="xs:float" />
|
||||
<xs:attribute name="CaStar" type="xs:float" />
|
||||
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Polynomial">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="QuadraticParabola">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Sine">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="SineLineCombination">
|
||||
<xs:complexType>
|
||||
<!-- Both parameters can be used -->
|
||||
<xs:attribute name="Lambda" type="xs:float" />
|
||||
<xs:attribute name="C" type="xs:float" />
|
||||
|
||||
<xs:attribute name="LambdaMode" type="cam:ValueMode" default="Absolute" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
|
||||
<xs:attribute name="LeftContinuity" type="cam:ElementContinuity" default="AsProfile" />
|
||||
<xs:attribute name="RightContinuity" type="cam:ElementContinuity" default="AsProfile" />
|
||||
<xs:attribute name="OptimizationGoal" type="cam:ElementOptimizationGoal" default="AsProfile" />
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="InverseSine">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="cam:SegmentBase">
|
||||
<xs:attribute name="InterpolationPointCount" type="xs:integer" default="32" />
|
||||
<xs:attribute name="MaxFollowingValueTolerance" type="xs:float" default="0.01" />
|
||||
<xs:attribute name="MathStartX" type="xs:float" default="-0.95" />
|
||||
<xs:attribute name="MathEndX" type="xs:float" default="0.95" />
|
||||
<xs:attribute name="Minimum" type="xs:float" />
|
||||
<xs:attribute name="Maximum" type="xs:float" />
|
||||
<xs:attribute name="Inversed" type="xs:boolean" default="false" />
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="Sine">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="cam:SegmentBase">
|
||||
<xs:attribute name="Amplitude" type="xs:float" default="1" />
|
||||
<!-- two of four are required and at least StartPhase or EndPhase is required -->
|
||||
<xs:attribute name="StartPhase" type="xs:float" default="0" />
|
||||
<xs:attribute name="EndPhase" type="xs:float" default="6.2831853071795862" />
|
||||
<xs:attribute name="Frequency" type="xs:float" default="1" />
|
||||
<xs:attribute name="PeriodLength" type="xs:float" default="1" />
|
||||
<!-- Two out of three are required here -->
|
||||
<xs:attribute name="Inclination" type="xs:float" default="0" />
|
||||
<xs:attribute name="StartOffset" type="xs:float" default="0" />
|
||||
<xs:attribute name="EndOffset" type="xs:float" default="0" />
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="PointGroup">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="cam:SegmentBase">
|
||||
|
||||
<!-- Allow points to be sub-elements of the group-->
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="Point" type="cam:PointElementType" />
|
||||
</xs:sequence>
|
||||
|
||||
<xs:attribute name="ApproximationDataPoints" type="xs:integer" default="32" />
|
||||
<xs:attribute name="ApproximationTolerance" type="xs:float" default="0.01" />
|
||||
<xs:attribute name="LeadingValueMode" type="cam:ValueMode" default="Absolute" />
|
||||
<xs:attribute name="FollowingValueMode" type="cam:ValueMode" default="Absolute" />
|
||||
<xs:attribute name="ApproximationMode" type="cam:PointGroupApproximationMode" default="SegmentApproximation" />
|
||||
<xs:attribute name="InterpolationMode" type="cam:PointGroupInterpolationMode" default="CubicSpline" />
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
|
@ -0,0 +1,144 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
|
||||
# Directorio donde se crearán los archivos de procesador
|
||||
PROCESSORS_DIR = "processors"
|
||||
|
||||
# Cabecera estándar para añadir a cada nuevo archivo
|
||||
FILE_HEADER = """# -*- coding: utf-8 -*-
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
"""
|
||||
|
||||
# Pie de página estándar con la función get_processor_info de plantilla
|
||||
def get_file_footer(func_name):
|
||||
"""Generates the standard footer with a placeholder get_processor_info."""
|
||||
type_name_guess = func_name.replace('process_', '')
|
||||
return f"""
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
\"\"\"Returns the type name and processing function for this module.\"\"\"
|
||||
# TODO: Adjust the type_name if needed (e.g., call, edge_detector, comparison, math).
|
||||
# TODO: Return a list if this module handles multiple types (e.g., PBox/NBox, FC/FB).
|
||||
type_name = "{type_name_guess}" # Basic guess
|
||||
return {{'type_name': type_name, 'processor_func': {func_name}}}
|
||||
"""
|
||||
|
||||
def extract_and_create_processors(source_py_file):
|
||||
"""
|
||||
Extracts top-level functions starting with 'process_' from the source file
|
||||
and creates individual processor files in the PROCESSORS_DIR, copying
|
||||
the entire function body until the next top-level definition.
|
||||
"""
|
||||
if not os.path.exists(source_py_file):
|
||||
print(f"Error: Source file not found: '{source_py_file}'")
|
||||
return
|
||||
|
||||
print(f"Reading source file: '{source_py_file}'")
|
||||
try:
|
||||
with open(source_py_file, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
except Exception as e:
|
||||
print(f"Error reading source file: {e}")
|
||||
return
|
||||
|
||||
os.makedirs(PROCESSORS_DIR, exist_ok=True)
|
||||
print(f"Ensuring '{PROCESSORS_DIR}' directory exists.")
|
||||
print("Searching for processor functions (def process_...):")
|
||||
|
||||
processor_functions = [] # Store tuples of (name, start_line_index, end_line_index)
|
||||
current_func_start = -1
|
||||
current_func_name = None
|
||||
|
||||
# Pattern to find ANY top-level function definition
|
||||
any_func_def_pattern = re.compile(r"^def\s+(\w+)\s*\(")
|
||||
# Pattern specific to processor functions
|
||||
process_func_def_pattern = re.compile(r"^def\s+(process_\w+)\s*\(")
|
||||
|
||||
# First pass: Identify start and end lines of all top-level functions
|
||||
for i, line in enumerate(lines):
|
||||
match = any_func_def_pattern.match(line)
|
||||
if match:
|
||||
# Found a new top-level function definition
|
||||
if current_func_name is not None:
|
||||
# Mark the end of the *previous* function
|
||||
# Only add if it was a 'process_' function
|
||||
if current_func_name.startswith("process_"):
|
||||
processor_functions.append((current_func_name, current_func_start, i))
|
||||
|
||||
# Start tracking the new function
|
||||
current_func_name = match.group(1)
|
||||
current_func_start = i
|
||||
|
||||
# Add the last function found in the file (if it was a process_ function)
|
||||
if current_func_name is not None and current_func_name.startswith("process_"):
|
||||
processor_functions.append((current_func_name, current_func_start, len(lines)))
|
||||
|
||||
# Second pass: Create files using the identified line ranges
|
||||
processor_count = 0
|
||||
if not processor_functions:
|
||||
print("\nWarning: No functions starting with 'process_' found at the top level.")
|
||||
return
|
||||
|
||||
print(f"Found {len(processor_functions)} potential processor functions.")
|
||||
|
||||
for func_name, start_idx, end_idx in processor_functions:
|
||||
print(f" - Processing: {func_name} (lines {start_idx+1}-{end_idx})")
|
||||
func_lines = lines[start_idx:end_idx] # Extract lines for this function
|
||||
# Remove trailing blank lines from the extracted block, often happens before next def
|
||||
while func_lines and func_lines[-1].strip() == "":
|
||||
func_lines.pop()
|
||||
|
||||
create_processor_file(func_name, func_lines)
|
||||
processor_count += 1
|
||||
|
||||
print(f"\nFinished processing. Attempted to create/check {processor_count} processor files in '{PROCESSORS_DIR}'.")
|
||||
|
||||
|
||||
def create_processor_file(func_name, func_lines):
|
||||
"""Creates the individual processor file if it doesn't exist."""
|
||||
target_filename = f"{func_name}.py"
|
||||
target_filepath = os.path.join(PROCESSORS_DIR, target_filename)
|
||||
|
||||
if os.path.exists(target_filepath):
|
||||
print(f" * Skipping: '{target_filename}' already exists.")
|
||||
return
|
||||
|
||||
print(f" * Creating: '{target_filename}'...")
|
||||
try:
|
||||
with open(target_filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(FILE_HEADER)
|
||||
# Write the function lines, ensuring consistent newline endings
|
||||
for line in func_lines:
|
||||
f.write(line.rstrip() + '\n')
|
||||
f.write(get_file_footer(func_name))
|
||||
except Exception as e:
|
||||
print(f" Error writing file '{target_filename}': {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Extracts 'process_*' functions from a source Python file "
|
||||
"and creates individual processor files."
|
||||
)
|
||||
parser.add_argument(
|
||||
"source_file",
|
||||
default="x2_process.py", # Valor por defecto
|
||||
nargs='?', # Hacerlo opcional para que use el default
|
||||
help="Path to the source Python file (default: x2_process.py)"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
extract_and_create_processors(args.source_file)
|
|
@ -0,0 +1,75 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_add(instruction, network_id, scl_map, access_map, data):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
en_input = instruction["inputs"].get("en")
|
||||
en_scl = (
|
||||
get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
if en_input
|
||||
else "TRUE"
|
||||
)
|
||||
in1_info = instruction["inputs"].get("in1")
|
||||
in2_info = instruction["inputs"].get("in2")
|
||||
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in1_scl is None or in2_scl is None:
|
||||
return False
|
||||
|
||||
target_scl = get_target_scl_name(
|
||||
instruction, "out", network_id, default_to_temp=True
|
||||
)
|
||||
if target_scl is None:
|
||||
print(f"Error: Sin destino ADD {instr_uid}")
|
||||
instruction["scl"] = f"// ERROR: Add {instr_uid} sin destino"
|
||||
instruction["type"] += "_error"
|
||||
return True
|
||||
|
||||
# Formatear operandos si son variables
|
||||
op1 = (
|
||||
format_variable_name(in1_scl)
|
||||
if in1_info and in1_info.get("type") == "variable"
|
||||
else in1_scl
|
||||
)
|
||||
op2 = (
|
||||
format_variable_name(in2_scl)
|
||||
if in2_info and in2_info.get("type") == "variable"
|
||||
else in2_scl
|
||||
)
|
||||
|
||||
# Añadir paréntesis si es necesario
|
||||
op1 = f"({op1})" if " " in op1 and not op1.startswith("(") else op1
|
||||
op2 = f"({op2})" if " " in op2 and not op2.startswith("(") else op2
|
||||
|
||||
scl_core = f"{target_scl} := {op1} + {op2};"
|
||||
scl_final = (
|
||||
f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
|
||||
)
|
||||
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = target_scl
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el procesador Add."""
|
||||
return {'type_name': 'add', 'processor_func': process_add, 'priority': 4}
|
|
@ -0,0 +1,112 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_blkmov(instruction, network_id, scl_map, access_map, data):
|
||||
"""
|
||||
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 # Ya procesado o con error
|
||||
|
||||
# --- 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
|
||||
|
||||
# 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
|
||||
|
||||
# --- 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
|
||||
|
||||
# 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:
|
||||
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}.")
|
||||
|
||||
if raw_dstblk_name is None:
|
||||
instruction["scl"] = f"// ERROR: BLKMOV {instr_uid} sin destino DSTBLK válido."
|
||||
instruction["type"] += "_error"
|
||||
return 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) ...
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el procesador BLKMOV."""
|
||||
# Asumiendo que 'BLKMOV' es el type en el JSON simplificado
|
||||
return {'type_name': 'blkmov', 'processor_func': process_blkmov, 'priority': 6}
|
|
@ -0,0 +1,141 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_call(instruction, network_id, scl_map, access_map, data):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction.get("type", "") # Usar get con default
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
block_name = instruction.get("block_name", f"UnknownCall_{instr_uid}")
|
||||
block_type = instruction.get("block_type") # FC, FB
|
||||
instance_db = instruction.get("instance_db") # Nombre del DB de instancia (para FB)
|
||||
|
||||
# Formatear nombres
|
||||
block_name_scl = format_variable_name(block_name)
|
||||
instance_db_scl = format_variable_name(instance_db) if instance_db else None
|
||||
|
||||
# --- Manejo de EN ---
|
||||
en_input = instruction["inputs"].get("en")
|
||||
en_scl = (
|
||||
get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
if en_input
|
||||
else "TRUE"
|
||||
)
|
||||
if en_scl is None:
|
||||
return False # Dependencia EN no resuelta
|
||||
|
||||
# --- Procesar Parámetros de Entrada/Salida ---
|
||||
# Necesitamos iterar sobre los pines definidos en la interfaz del bloque llamado.
|
||||
# Esta información no está directamente en la instrucción 'Call' del JSON simplificado.
|
||||
# ¡Limitación! Sin la interfaz del bloque llamado, solo podemos manejar EN/ENO
|
||||
# y asumir una llamada sin parámetros o con parámetros conectados implícitamente.
|
||||
|
||||
# Solución temporal: Buscar conexiones en 'inputs' y 'outputs' que NO sean 'en'/'eno'
|
||||
# y construir la llamada basándose en eso. Esto es muy heurístico.
|
||||
scl_call_params = []
|
||||
processed_inputs = {"en"} # Marcar 'en' como ya procesado
|
||||
for pin_name, source_info in instruction.get("inputs", {}).items():
|
||||
if pin_name not in processed_inputs:
|
||||
param_scl = get_scl_representation(
|
||||
source_info, network_id, scl_map, access_map
|
||||
)
|
||||
if param_scl is None:
|
||||
# print(f"DEBUG: Call {instr_uid} esperando parámetro de entrada {pin_name}")
|
||||
return False # Dependencia de parámetro no resuelta
|
||||
# Formatear si es variable
|
||||
param_scl_formatted = (
|
||||
format_variable_name(param_scl)
|
||||
if source_info.get("type") == "variable"
|
||||
else param_scl
|
||||
)
|
||||
scl_call_params.append(
|
||||
f"{format_variable_name(pin_name)} := {param_scl_formatted}"
|
||||
)
|
||||
processed_inputs.add(pin_name)
|
||||
|
||||
# Procesar parámetros de salida (asignaciones después de la llamada o pasados como VAR_IN_OUT/VAR_OUTPUT)
|
||||
# Esto es aún más complejo. SCL normalmente asigna salidas después o usa punteros/referencias.
|
||||
# Simplificación: Asumir que las salidas se manejan por asignación posterior si es necesario,
|
||||
# o que son VAR_OUTPUT y se acceden como instancia.salida.
|
||||
# Por ahora, no generamos asignaciones explícitas para las salidas aquí.
|
||||
|
||||
# --- Construcción de la Llamada SCL ---
|
||||
scl_call_body = ""
|
||||
param_string = ", ".join(scl_call_params)
|
||||
|
||||
if block_type == "FB":
|
||||
if not instance_db_scl:
|
||||
print(
|
||||
f"Error: Llamada a FB '{block_name_scl}' (UID {instr_uid}) sin DB de instancia especificado."
|
||||
)
|
||||
instruction["scl"] = f"// ERROR: FB Call {block_name_scl} sin instancia"
|
||||
instruction["type"] = "Call_FB_error"
|
||||
return True # Procesado con error
|
||||
# Llamada a FB con DB de instancia
|
||||
scl_call_body = f"{instance_db_scl}({param_string});"
|
||||
elif block_type == "FC":
|
||||
# Llamada a FC
|
||||
scl_call_body = f"{block_name_scl}({param_string});"
|
||||
else:
|
||||
print(
|
||||
f"Advertencia: Tipo de bloque no soportado para Call UID {instr_uid}: {block_type}"
|
||||
)
|
||||
scl_call_body = f"// ERROR: Call a bloque tipo '{block_type}' no soportado: {block_name_scl}"
|
||||
instruction["type"] = f"Call_{block_type}_error" # Marcar como error parcial
|
||||
|
||||
# --- Aplicar Condición EN ---
|
||||
scl_final = ""
|
||||
if en_scl != "TRUE":
|
||||
# Indentar la llamada dentro del IF
|
||||
indented_call = "\n".join([f" {line}" for line in scl_call_body.splitlines()])
|
||||
scl_final = f"IF {en_scl} THEN\n{indented_call}\nEND_IF;"
|
||||
else:
|
||||
scl_final = scl_call_body
|
||||
|
||||
# --- Actualizar JSON y Mapa SCL ---
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = (
|
||||
f"Call_{block_type}_scl"
|
||||
if "_error" not in instruction["type"]
|
||||
else instruction["type"]
|
||||
)
|
||||
|
||||
# Actualizar scl_map con el estado ENO (igual a EN para llamadas simples sin manejo explícito de ENO)
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl
|
||||
|
||||
# Propagar valores de salida (si pudiéramos determinarlos)
|
||||
# Ejemplo: Si supiéramos que hay una salida 'Out1' de tipo INT
|
||||
# map_key_out1 = (network_id, instr_uid, "Out1")
|
||||
# if block_type == "FB" and instance_db_scl:
|
||||
# scl_map[map_key_out1] = f"{instance_db_scl}.Out1" # Acceso a salida de instancia
|
||||
# else:
|
||||
# # Para FCs, necesitaríamos una variable temporal o asignación explícita
|
||||
# temp_out1 = generate_temp_var_name(network_id, instr_uid, "Out1")
|
||||
# # Modificar scl_call_body para incluir la asignación: Out1 => temp_out1
|
||||
# scl_map[map_key_out1] = temp_out1
|
||||
|
||||
return True
|
||||
|
||||
# --- Procesador de Temporizadores (TON, TOF) ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para las llamadas a FC y FB."""
|
||||
# Esta función maneja tanto FC como FB. El despachador en x2_process.py
|
||||
# usará 'call_fc' o 'call_fb' como clave basada en block_type.
|
||||
return [
|
||||
{'type_name': 'call_fc', 'processor_func': process_call, 'priority': 6},
|
||||
{'type_name': 'call_fb', 'processor_func': process_call, 'priority': 6}
|
||||
]
|
|
@ -0,0 +1,79 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_coil(instruction, network_id, scl_map, access_map, data):
|
||||
"""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
|
||||
|
||||
# EN x2_process.py, junto a otras funciones process_xxx
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el procesador Coil."""
|
||||
return {'type_name': 'coil', 'processor_func': process_coil, 'priority': 3}
|
|
@ -0,0 +1,81 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_comparison(instruction, network_id, scl_map, access_map, data):
|
||||
"""
|
||||
Genera la expresión SCL para Comparadores (GT, LT, GE, LE, NE).
|
||||
El resultado se propaga por scl_map['out'].
|
||||
"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"] # GT, LT, GE, LE, NE
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
# Mapa de tipos a operadores SCL
|
||||
op_map = {"GT": ">", "LT": "<", "GE": ">=", "LE": "<=", "NE": "<>"}
|
||||
scl_operator = op_map.get(instr_type)
|
||||
if not scl_operator:
|
||||
instruction["scl"] = f"// ERROR: Tipo de comparación no soportado: {instr_type}"
|
||||
instruction["type"] += "_error"
|
||||
return True
|
||||
|
||||
# Obtener operandos
|
||||
in1_info = instruction["inputs"].get("in1")
|
||||
in2_info = instruction["inputs"].get("in2")
|
||||
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
|
||||
|
||||
if in1_scl is None or in2_scl is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# Formatear operandos si son variables
|
||||
op1 = format_variable_name(in1_scl) if in1_info and in1_info.get("type") == "variable" else in1_scl
|
||||
op2 = format_variable_name(in2_scl) if in2_info and in2_info.get("type") == "variable" else in2_scl
|
||||
|
||||
# Añadir paréntesis si contienen espacios (poco probable tras formatear)
|
||||
op1 = f"({op1})" if " " in op1 and not op1.startswith("(") else op1
|
||||
op2 = f"({op2})" if " " in op2 and not op2.startswith("(") else op2
|
||||
|
||||
comparison_scl = f"{op1} {scl_operator} {op2}"
|
||||
|
||||
# Guardar resultado en el mapa para 'out'
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = f"({comparison_scl})" # Poner paréntesis por seguridad
|
||||
|
||||
# Manejar entrada 'pre'/RLO -> ENO (como en EQ)
|
||||
pre_input = instruction["inputs"].get("pre") # Asumir 'pre' como en EQ
|
||||
en_scl = get_scl_representation(pre_input, network_id, scl_map, access_map) if pre_input else "TRUE"
|
||||
if en_scl is None:
|
||||
return False # Dependencia 'pre'/'en' no lista
|
||||
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl
|
||||
|
||||
instruction["scl"] = f"// Comparison {instr_type} {instr_uid}: {comparison_scl}"
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
# --- Procesador de Matemáticas (ADD ya existe, añadir otros) ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para los comparadores (excepto EQ)."""
|
||||
# Esta función maneja múltiples tipos de comparación.
|
||||
return [
|
||||
{'type_name': 'gt', 'processor_func': process_comparison, 'priority': 2}, # >
|
||||
{'type_name': 'lt', 'processor_func': process_comparison, 'priority': 2}, # <
|
||||
{'type_name': 'ge', 'processor_func': process_comparison, 'priority': 2}, # >=
|
||||
{'type_name': 'le', 'processor_func': process_comparison, 'priority': 2}, # <=
|
||||
{'type_name': 'ne', 'processor_func': process_comparison, 'priority': 2} # <>
|
||||
]
|
|
@ -0,0 +1,73 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_contact(instruction, network_id, scl_map, access_map, data):
|
||||
"""Traduce Contact (normal o negado) a una expresión booleana SCL."""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
# --- INICIO LEER NEGACIÓN ---
|
||||
# Verificar si el pin 'operand' está marcado como negado en el JSON
|
||||
is_negated = instruction.get("negated_pins", {}).get("operand", False)
|
||||
# --- FIN LEER NEGACIÓN ---
|
||||
|
||||
# print(f"DEBUG: Intentando procesar CONTACT{' (N)' if is_negated else ''} - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
in_input = instruction["inputs"].get("in")
|
||||
in_rlo_scl = (
|
||||
"TRUE"
|
||||
if in_input is None
|
||||
else get_scl_representation(in_input, network_id, scl_map, access_map)
|
||||
)
|
||||
operand_scl = get_scl_representation(
|
||||
instruction["inputs"].get("operand"), network_id, scl_map, access_map
|
||||
)
|
||||
|
||||
if in_rlo_scl is None or operand_scl is None:
|
||||
return False
|
||||
|
||||
# Usar is_negated para aplicar NOT
|
||||
term = f"NOT {operand_scl}" if is_negated else operand_scl
|
||||
if not (term.startswith('"') and term.endswith('"')):
|
||||
# Añadir paréntesis si es NOT o si contiene espacios/operadores
|
||||
if is_negated or (
|
||||
" " in term and not (term.startswith("(") and term.endswith(")"))
|
||||
):
|
||||
term = f"({term})"
|
||||
|
||||
new_rlo_scl = (
|
||||
term
|
||||
if in_rlo_scl == "TRUE"
|
||||
else (
|
||||
f"({in_rlo_scl}) AND {term}"
|
||||
if ("AND" in in_rlo_scl or "OR" in in_rlo_scl)
|
||||
and not (in_rlo_scl.startswith("(") and in_rlo_scl.endswith(")"))
|
||||
else f"{in_rlo_scl} AND {term}"
|
||||
)
|
||||
)
|
||||
|
||||
map_key = (network_id, instr_uid, "out")
|
||||
scl_map[map_key] = new_rlo_scl
|
||||
instruction["scl"] = f"// RLO: {new_rlo_scl}"
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
# --- process_edge_detector MODIFICADA ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el procesador Contact."""
|
||||
return {'type_name': 'contact', 'processor_func': process_contact, 'priority': 1}
|
|
@ -0,0 +1,81 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_convert(instruction, network_id, scl_map, access_map, data):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
en_input = instruction["inputs"].get("en")
|
||||
en_scl = (
|
||||
get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
if en_input
|
||||
else "TRUE"
|
||||
)
|
||||
in_info = instruction["inputs"].get("in")
|
||||
in_scl = get_scl_representation(in_info, network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in_scl is None:
|
||||
return False # Esperar si dependencias no listas
|
||||
|
||||
target_scl = get_target_scl_name(
|
||||
instruction, "out", network_id, default_to_temp=True
|
||||
)
|
||||
if target_scl is None:
|
||||
print(f"Error: Sin destino claro para CONVERT {instr_uid}")
|
||||
instruction["scl"] = f"// ERROR: Convert {instr_uid} sin destino"
|
||||
instruction["type"] += "_error"
|
||||
return True # Procesado con error
|
||||
|
||||
# Formatear entrada si es variable
|
||||
in_scl_formatted = (
|
||||
format_variable_name(in_scl)
|
||||
if in_info and in_info.get("type") == "variable"
|
||||
else in_scl
|
||||
)
|
||||
|
||||
# Determinar el tipo de destino (simplificado, necesitaría info del XML original)
|
||||
# Asumimos que el tipo está en TemplateValues o inferirlo del nombre/contexto
|
||||
target_type = instruction.get("template_values", {}).get(
|
||||
"destType", "VARIANT"
|
||||
) # Ejemplo, ajustar según XML real
|
||||
conversion_func = f"{target_type}_TO_" # Necesita el tipo de origen también
|
||||
# Esta parte es compleja sin saber los tipos exactos. Usaremos una conversión genérica o MOVE.
|
||||
# Para una conversión real, necesitaríamos algo como:
|
||||
# conversion_expr = f"CONVERT(IN := {in_scl_formatted}, OUT => {target_scl})" # Sintaxis inventada
|
||||
# O usar funciones específicas: INT_TO_REAL, etc.
|
||||
|
||||
# Simplificación: Usar asignación directa (MOVE implícito) o función genérica si existe
|
||||
# Asumiremos asignación directa por ahora.
|
||||
conversion_expr = in_scl_formatted
|
||||
scl_core = f"{target_scl} := {conversion_expr};"
|
||||
|
||||
# Añadir IF EN si es necesario
|
||||
scl_final = (
|
||||
f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
|
||||
)
|
||||
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = target_scl # El valor de salida es el contenido del destino
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl # ENO sigue a EN
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el procesador Convert."""
|
||||
return {'type_name': 'convert', 'processor_func': process_convert, 'priority': 4}
|
|
@ -0,0 +1,94 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_counter(instruction, network_id, scl_map, access_map, data):
|
||||
"""
|
||||
Genera SCL para Contadores (CTU, CTD, CTUD).
|
||||
Requiere datos de instancia (DB o STAT).
|
||||
"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"] # CTU, CTD, CTUD
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
# 1. Obtener Inputs (varía según tipo)
|
||||
params = []
|
||||
resolved = True
|
||||
|
||||
input_pins = []
|
||||
if instr_type == "CTU": input_pins = ["CU", "R", "PV"]
|
||||
elif instr_type == "CTD": input_pins = ["CD", "LD", "PV"]
|
||||
elif instr_type == "CTUD": input_pins = ["CU", "CD", "R", "LD", "PV"]
|
||||
else:
|
||||
instruction["scl"] = f"// ERROR: Tipo de contador no soportado: {instr_type}"
|
||||
instruction["type"] += "_error"
|
||||
return True # Procesado con error
|
||||
|
||||
for pin in input_pins:
|
||||
pin_info = instruction["inputs"].get(pin)
|
||||
if pin_info is None and pin not in ["R", "LD"]: # R y LD pueden no estar conectados
|
||||
print(f"Error: Falta entrada requerida '{pin}' para {instr_type} UID {instr_uid}.")
|
||||
# Permitir continuar si solo faltan R o LD opcionales? Por ahora no.
|
||||
instruction["scl"] = f"// ERROR: Falta entrada requerida '{pin}' para {instr_type} UID {instr_uid}."
|
||||
instruction["type"] += "_error"
|
||||
return True # Error
|
||||
elif pin_info: # Si el pin existe en el JSON
|
||||
scl_pin = get_scl_representation(pin_info, network_id, scl_map, access_map)
|
||||
if scl_pin is None:
|
||||
resolved = False
|
||||
break # Salir si una dependencia no está lista
|
||||
scl_pin_formatted = format_variable_name(scl_pin) if pin_info.get("type") == "variable" else scl_pin
|
||||
params.append(f"{pin} := {scl_pin_formatted}")
|
||||
|
||||
if not resolved: return False
|
||||
|
||||
# 2. Obtener Nombre de Instancia (NECESITA MEJORA EN x1.py)
|
||||
instance_name = instruction.get("instance_db")
|
||||
if not instance_name:
|
||||
instance_name = f"#COUNTER_INSTANCE_{instr_uid}" # Placeholder
|
||||
print(f"Advertencia: No se encontró instancia para {instr_type} UID {instr_uid}. Usando placeholder '{instance_name}'. Ajustar x1.py y declarar en x3.py.")
|
||||
else:
|
||||
instance_name = format_variable_name(instance_name)
|
||||
|
||||
# 3. Generar la llamada SCL
|
||||
param_string = ", ".join(params)
|
||||
scl_call = f"{instance_name}({param_string}); // TODO: Declarar {instance_name} : {instr_type}; en VAR_STAT o VAR"
|
||||
|
||||
instruction["scl"] = scl_call
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# 4. Actualizar scl_map para las salidas (QU, QD, CV)
|
||||
output_pins = []
|
||||
if instr_type == "CTU": output_pins = ["QU", "CV"]
|
||||
elif instr_type == "CTD": output_pins = ["QD", "CV"]
|
||||
elif instr_type == "CTUD": output_pins = ["QU", "QD", "CV"]
|
||||
|
||||
for pin in output_pins:
|
||||
map_key = (network_id, instr_uid, pin)
|
||||
scl_map[map_key] = f"{instance_name}.{pin}"
|
||||
# Contadores no tienen ENO estándar en LAD/FBD
|
||||
|
||||
return True
|
||||
|
||||
# --- Procesador de Comparadores (EQ ya existe, añadir otros) ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para los contadores CTU, CTD, CTUD."""
|
||||
# Asumiendo que los tipos en el JSON son CTU, CTD, CTUD
|
||||
return [
|
||||
{'type_name': 'ctu', 'processor_func': process_counter, 'priority': 5},
|
||||
{'type_name': 'ctd', 'processor_func': process_counter, 'priority': 5},
|
||||
{'type_name': 'ctud', 'processor_func': process_counter, 'priority': 5}
|
||||
]
|
|
@ -0,0 +1,91 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_edge_detector(instruction, network_id, scl_map, access_map, data):
|
||||
"""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) ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para los detectores de flanco PBox (P_TRIG) y NBox (N_TRIG)."""
|
||||
return [
|
||||
{'type_name': 'pbox', 'processor_func': process_edge_detector, 'priority': 2}, # Flanco positivo
|
||||
{'type_name': 'nbox', 'processor_func': process_edge_detector, 'priority': 2} # Flanco negativo
|
||||
]
|
|
@ -0,0 +1,74 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_eq(instruction, network_id, scl_map, access_map, data):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
in1_info = instruction["inputs"].get("in1")
|
||||
in2_info = instruction["inputs"].get("in2")
|
||||
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
|
||||
|
||||
if in1_scl is None or in2_scl is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# Formatear operandos si son variables
|
||||
op1 = (
|
||||
format_variable_name(in1_scl)
|
||||
if in1_info and in1_info.get("type") == "variable"
|
||||
else in1_scl
|
||||
)
|
||||
op2 = (
|
||||
format_variable_name(in2_scl)
|
||||
if in2_info and in2_info.get("type") == "variable"
|
||||
else in2_scl
|
||||
)
|
||||
|
||||
# Añadir paréntesis si los operandos contienen espacios (poco probable después de formatear)
|
||||
op1 = f"({op1})" if " " in op1 and not op1.startswith("(") else op1
|
||||
op2 = f"({op2})" if " " in op2 and not op2.startswith("(") else op2
|
||||
|
||||
comparison_scl = f"{op1} = {op2}"
|
||||
|
||||
# Guardar el resultado booleano de la comparación en el mapa SCL para la salida 'out'
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = comparison_scl
|
||||
|
||||
# Procesar la entrada 'pre' (RLO anterior) para determinar ENO
|
||||
pre_input = instruction["inputs"].get("pre")
|
||||
pre_scl = (
|
||||
"TRUE"
|
||||
if pre_input is None
|
||||
else get_scl_representation(pre_input, network_id, scl_map, access_map)
|
||||
)
|
||||
if pre_scl is None:
|
||||
return False # Dependencia 'pre' no lista
|
||||
|
||||
# Guardar el estado de 'pre' como ENO
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = pre_scl
|
||||
|
||||
# El SCL generado es solo un comentario indicando la condición,
|
||||
# ya que la lógica se propaga a través de scl_map['out']
|
||||
instruction["scl"] = f"// Comparison Eq {instr_uid}: {comparison_scl}"
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el comparador de igualdad (EQ)."""
|
||||
return {'type_name': 'eq', 'processor_func': process_eq, 'priority': 2}
|
|
@ -0,0 +1,82 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_math(instruction, network_id, scl_map, access_map, data):
|
||||
"""
|
||||
Genera SCL para operaciones matemáticas (SUB, MUL, DIV).
|
||||
"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"] # SUB, MUL, DIV
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
# Mapa de tipos a operadores SCL
|
||||
op_map = {"SUB": "-", "MUL": "*", "DIV": "/"}
|
||||
scl_operator = op_map.get(instr_type)
|
||||
if not scl_operator:
|
||||
instruction["scl"] = f"// ERROR: Operación matemática no soportada: {instr_type}"
|
||||
instruction["type"] += "_error"
|
||||
return True
|
||||
|
||||
# Obtener EN, IN1, IN2
|
||||
en_input = instruction["inputs"].get("en")
|
||||
in1_info = instruction["inputs"].get("in1")
|
||||
in2_info = instruction["inputs"].get("in2")
|
||||
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) if en_input else "TRUE"
|
||||
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in1_scl is None or in2_scl is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# Obtener destino 'out'
|
||||
target_scl = get_target_scl_name(instruction, "out", network_id, default_to_temp=True)
|
||||
if target_scl is None:
|
||||
instruction["scl"] = f"// ERROR: {instr_type} {instr_uid} sin destino 'out'."
|
||||
instruction["type"] += "_error"
|
||||
return True
|
||||
|
||||
# Formatear operandos si son variables
|
||||
op1 = format_variable_name(in1_scl) if in1_info and in1_info.get("type") == "variable" else in1_scl
|
||||
op2 = format_variable_name(in2_scl) if in2_info and in2_info.get("type") == "variable" else in2_scl
|
||||
|
||||
# Añadir paréntesis si es necesario (especialmente para expresiones)
|
||||
op1 = f"({op1})" if (" " in op1 or "+" in op1 or "-" in op1 or "*" in op1 or "/" in op1) and not op1.startswith("(") else op1
|
||||
op2 = f"({op2})" if (" " in op2 or "+" in op2 or "-" in op2 or "*" in op2 or "/" in op2) and not op2.startswith("(") else op2
|
||||
|
||||
# Generar SCL
|
||||
scl_core = f"{target_scl} := {op1} {scl_operator} {op2};"
|
||||
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
|
||||
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Actualizar mapa SCL
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = target_scl
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl
|
||||
return True
|
||||
|
||||
# --- Procesador NOT ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para operaciones matemáticas (excepto ADD, MOD)."""
|
||||
# Esta función maneja SUB, MUL, DIV.
|
||||
return [
|
||||
{'type_name': 'sub', 'processor_func': process_math, 'priority': 4}, # Resta
|
||||
{'type_name': 'mul', 'processor_func': process_math, 'priority': 4}, # Multiplicación
|
||||
{'type_name': 'div', 'processor_func': process_math, 'priority': 4} # División
|
||||
]
|
|
@ -0,0 +1,76 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_mod(instruction, network_id, scl_map, access_map, data):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
en_input = instruction["inputs"].get("en")
|
||||
en_scl = (
|
||||
get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
if en_input
|
||||
else "TRUE"
|
||||
)
|
||||
in1_info = instruction["inputs"].get("in1")
|
||||
in2_info = instruction["inputs"].get("in2")
|
||||
in1_scl = get_scl_representation(in1_info, network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(in2_info, network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in1_scl is None or in2_scl is None:
|
||||
return False
|
||||
|
||||
target_scl = get_target_scl_name(
|
||||
instruction, "out", network_id, default_to_temp=True
|
||||
)
|
||||
if target_scl is None:
|
||||
print(f"Error: Sin destino MOD {instr_uid}")
|
||||
instruction["scl"] = f"// ERROR: Mod {instr_uid} sin destino"
|
||||
instruction["type"] += "_error"
|
||||
return True
|
||||
|
||||
# Formatear operandos si son variables
|
||||
op1 = (
|
||||
format_variable_name(in1_scl)
|
||||
if in1_info and in1_info.get("type") == "variable"
|
||||
else in1_scl
|
||||
)
|
||||
op2 = (
|
||||
format_variable_name(in2_scl)
|
||||
if in2_info and in2_info.get("type") == "variable"
|
||||
else in2_scl
|
||||
)
|
||||
|
||||
# Añadir paréntesis si es necesario (poco probable tras formatear)
|
||||
op1 = f"({op1})" if " " in op1 and not op1.startswith("(") else op1
|
||||
op2 = f"({op2})" if " " in op2 and not op2.startswith("(") else op2
|
||||
|
||||
scl_core = f"{target_scl} := {op1} MOD {op2};"
|
||||
scl_final = (
|
||||
f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
|
||||
)
|
||||
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = target_scl
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para la operación Modulo."""
|
||||
return {'type_name': 'mod', 'processor_func': process_mod, 'priority': 4}
|
|
@ -0,0 +1,84 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_move(instruction, network_id, scl_map, access_map, data):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
en_input = instruction["inputs"].get("en")
|
||||
en_scl = (
|
||||
get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
if en_input
|
||||
else "TRUE"
|
||||
)
|
||||
in_info = instruction["inputs"].get("in")
|
||||
in_scl = get_scl_representation(in_info, network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in_scl is None:
|
||||
return False
|
||||
|
||||
# Intentar obtener el destino de 'out1' (o 'out' si es el estándar)
|
||||
target_scl = get_target_scl_name(
|
||||
instruction, "out1", network_id, default_to_temp=False
|
||||
)
|
||||
if target_scl is None:
|
||||
target_scl = get_target_scl_name(
|
||||
instruction, "out", network_id, default_to_temp=False
|
||||
)
|
||||
|
||||
if target_scl is None:
|
||||
# Si no hay destino explícito, podríamos usar una temp si la lógica lo requiere,
|
||||
# pero MOVE generalmente necesita un destino claro. Marcar como advertencia/error.
|
||||
print(
|
||||
f"Advertencia/Error: MOVE {instr_uid} sin destino claro en 'out' o 'out1'. Se requiere destino explícito."
|
||||
)
|
||||
# Decidir si generar error o simplemente no hacer nada. No hacer nada es más seguro.
|
||||
# instruction["scl"] = f"// ERROR: MOVE {instr_uid} sin destino"
|
||||
# instruction["type"] += "_error"
|
||||
# return True
|
||||
return False # No procesar si no hay destino claro
|
||||
|
||||
# Formatear entrada si es variable
|
||||
in_scl_formatted = (
|
||||
format_variable_name(in_scl)
|
||||
if in_info and in_info.get("type") == "variable"
|
||||
else in_scl
|
||||
)
|
||||
|
||||
scl_core = f"{target_scl} := {in_scl_formatted};"
|
||||
scl_final = (
|
||||
f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" if en_scl != "TRUE" else scl_core
|
||||
)
|
||||
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Propagar el valor movido a través de scl_map si se usa 'out' o 'out1' como fuente
|
||||
map_key_out = (network_id, instr_uid, "out") # Asumir 'out' como estándar
|
||||
scl_map[map_key_out] = target_scl # El valor es lo que está en el destino
|
||||
map_key_out1 = (network_id, instr_uid, "out1") # Si existe out1
|
||||
scl_map[map_key_out1] = target_scl
|
||||
|
||||
map_key_eno = (network_id, instr_uid, "eno")
|
||||
scl_map[map_key_eno] = en_scl
|
||||
return True
|
||||
|
||||
# EN x2_process.py
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para la operación Move."""
|
||||
return {'type_name': 'move', 'processor_func': process_move, 'priority': 3}
|
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_not(instruction, network_id, scl_map, access_map, data):
|
||||
"""Genera la expresión SCL para la inversión lógica NOT."""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"] # Not
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
in_info = instruction["inputs"].get("in")
|
||||
in_scl = get_scl_representation(in_info, network_id, scl_map, access_map)
|
||||
|
||||
if in_scl is None:
|
||||
return False # Dependencia no lista
|
||||
|
||||
# Formatear entrada (añadir paréntesis si es complejo)
|
||||
in_scl_formatted = in_scl
|
||||
if (" " in in_scl or "AND" in in_scl or "OR" in in_scl) and not (in_scl.startswith("(") and in_scl.endswith(")")):
|
||||
in_scl_formatted = f"({in_scl})"
|
||||
|
||||
result_scl = f"NOT {in_scl_formatted}"
|
||||
|
||||
# Guardar resultado en mapa para 'out'
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = result_scl
|
||||
|
||||
instruction["scl"] = f"// Logic NOT {instr_uid}: {result_scl}"
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
# NOT no tiene EN/ENO explícito en LAD, modifica el RLO
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para la operación Not."""
|
||||
return {'type_name': 'not', 'processor_func': process_not, 'priority': 1}
|
|
@ -0,0 +1,80 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_o(instruction, network_id, scl_map, access_map, data):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
# Buscar todas las entradas 'in', 'in1', 'in2', ...
|
||||
input_pins = sorted([pin for pin in instruction["inputs"] if pin.startswith("in")])
|
||||
|
||||
if not input_pins:
|
||||
print(f"Error: O {instr_uid} sin pines de entrada (inX).")
|
||||
instruction["scl"] = f"// ERROR: O {instr_uid} sin pines inX"
|
||||
instruction["type"] += "_error"
|
||||
return True # Procesado con error
|
||||
|
||||
scl_parts = []
|
||||
all_resolved = True
|
||||
for pin in input_pins:
|
||||
in_scl = get_scl_representation(
|
||||
instruction["inputs"][pin], network_id, scl_map, access_map
|
||||
)
|
||||
if in_scl is None:
|
||||
all_resolved = False
|
||||
# print(f"DEBUG: O {instr_uid} esperando pin {pin}")
|
||||
break # Salir del bucle for si una entrada no está lista
|
||||
|
||||
# Formatear término (añadir paréntesis si es necesario)
|
||||
term = in_scl
|
||||
if (" " in term or "AND" in term) and not (
|
||||
term.startswith("(") and term.endswith(")")
|
||||
):
|
||||
term = f"({term})"
|
||||
scl_parts.append(term)
|
||||
|
||||
if not all_resolved:
|
||||
return False # Esperar a que todas las entradas estén resueltas
|
||||
|
||||
# Construir la expresión OR
|
||||
result_scl = "FALSE" # Valor por defecto si no hay entradas válidas (raro)
|
||||
if scl_parts:
|
||||
result_scl = " OR ".join(scl_parts)
|
||||
# Simplificar si solo hay un término
|
||||
if len(scl_parts) == 1:
|
||||
result_scl = scl_parts[0]
|
||||
# Quitar paréntesis redundantes si solo hay un término y está entre paréntesis
|
||||
if result_scl.startswith("(") and result_scl.endswith(")"):
|
||||
# Comprobar si los paréntesis son necesarios (contienen operadores de menor precedencia)
|
||||
# Simplificación: quitar siempre si solo hay un término. Podría ser incorrecto en casos complejos.
|
||||
# result_scl = result_scl[1:-1] # Comentado por seguridad
|
||||
pass
|
||||
|
||||
# Actualizar mapa SCL y la instrucción
|
||||
map_key_out = (network_id, instr_uid, "out")
|
||||
scl_map[map_key_out] = result_scl
|
||||
instruction["scl"] = (
|
||||
f"// Logic O {instr_uid}: {result_scl}" # Comentario informativo
|
||||
)
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# La instrucción 'O' no tiene ENO propio, propaga el resultado por 'out'
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para la operación lógica O (OR)."""
|
||||
return {'type_name': 'o', 'processor_func': process_o, 'priority': 1}
|
|
@ -0,0 +1,59 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_rcoil(instruction, network_id, scl_map, access_map, data ):
|
||||
"""Genera SCL para Reset Coil (RCoil): IF condition THEN variable := FALSE; END_IF;"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False # Ya procesado o con error
|
||||
|
||||
# Obtener condición de entrada (RLO)
|
||||
in_info = instruction["inputs"].get("in")
|
||||
condition_scl = get_scl_representation(in_info, network_id, scl_map, access_map)
|
||||
|
||||
# Obtener operando (variable a poner a FALSE)
|
||||
operand_info = instruction["inputs"].get("operand")
|
||||
variable_scl = get_scl_representation(operand_info, network_id, scl_map, access_map)
|
||||
|
||||
# Verificar dependencias
|
||||
if condition_scl is None or variable_scl is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# Verificar que el operando sea una variable
|
||||
if not (operand_info and operand_info.get("type") == "variable"):
|
||||
print(f"Error: RCoil {instr_uid} operando no es variable o falta info (Tipo: {operand_info.get('type')}).")
|
||||
instruction["scl"] = f"// ERROR: RCoil {instr_uid} operando no es variable."
|
||||
instruction["type"] += "_error"
|
||||
return True # Procesado con error
|
||||
|
||||
# Formatear nombre de variable
|
||||
variable_name_formatted = format_variable_name(variable_scl)
|
||||
|
||||
# Generar SCL
|
||||
scl_core = f"{variable_name_formatted} := FALSE;"
|
||||
scl_final = (
|
||||
f"IF {condition_scl} THEN\n {scl_core}\nEND_IF;" if condition_scl != "TRUE" else scl_core
|
||||
)
|
||||
|
||||
# Actualizar instrucción
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
# RCoil no genera salida 'out' ni 'eno' significativas para propagar
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para la bobina Reset (RCoil)."""
|
||||
return {'type_name': 'rcoil', 'processor_func': process_rcoil, 'priority': 3}
|
|
@ -0,0 +1,59 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_scoil(instruction, network_id, scl_map, access_map, data):
|
||||
"""Genera SCL para Set Coil (SCoil): IF condition THEN variable := TRUE; END_IF;"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"]
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False # Ya procesado o con error
|
||||
|
||||
# Obtener condición de entrada (RLO)
|
||||
in_info = instruction["inputs"].get("in")
|
||||
condition_scl = get_scl_representation(in_info, network_id, scl_map, access_map)
|
||||
|
||||
# Obtener operando (variable a poner a TRUE)
|
||||
operand_info = instruction["inputs"].get("operand")
|
||||
variable_scl = get_scl_representation(operand_info, network_id, scl_map, access_map)
|
||||
|
||||
# Verificar dependencias
|
||||
if condition_scl is None or variable_scl is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# Verificar que el operando sea una variable
|
||||
if not (operand_info and operand_info.get("type") == "variable"):
|
||||
print(f"Error: SCoil {instr_uid} operando no es variable o falta info (Tipo: {operand_info.get('type')}).")
|
||||
instruction["scl"] = f"// ERROR: SCoil {instr_uid} operando no es variable."
|
||||
instruction["type"] += "_error"
|
||||
return True # Procesado con error
|
||||
|
||||
# Formatear nombre de variable
|
||||
variable_name_formatted = format_variable_name(variable_scl)
|
||||
|
||||
# Generar SCL
|
||||
scl_core = f"{variable_name_formatted} := TRUE;"
|
||||
scl_final = (
|
||||
f"IF {condition_scl} THEN\n {scl_core}\nEND_IF;" if condition_scl != "TRUE" else scl_core
|
||||
)
|
||||
|
||||
# Actualizar instrucción
|
||||
instruction["scl"] = scl_final
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
# SCoil no genera salida 'out' ni 'eno' significativas para propagar
|
||||
return True
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para la bobina Set (SCoil)."""
|
||||
return {'type_name': 'scoil', 'processor_func': process_scoil, 'priority': 3}
|
|
@ -0,0 +1,73 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_sd(instruction, network_id, scl_map, access_map, data):
|
||||
"""
|
||||
Genera SCL para Temporizador On-Delay (Sd -> TON).
|
||||
Requiere datos de instancia (DB o STAT/TEMP).
|
||||
"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = "Sd" # Tipo original LAD
|
||||
if instruction["type"].endswith(SCL_SUFFIX) or "_error" in instruction["type"]:
|
||||
return False
|
||||
|
||||
# 1. Obtener Inputs: s (start), tv (time value)
|
||||
# El pin 'r' (reset) no tiene equivalente directo en TON, se ignora aquí.
|
||||
s_info = instruction["inputs"].get("s")
|
||||
tv_info = instruction["inputs"].get("tv")
|
||||
timer_instance_info = instruction["inputs"].get("timer") # Esperando que x1 lo extraiga
|
||||
|
||||
scl_s = get_scl_representation(s_info, network_id, scl_map, access_map)
|
||||
scl_tv = get_scl_representation(tv_info, network_id, scl_map, access_map)
|
||||
scl_instance_name = get_scl_representation(timer_instance_info, network_id, scl_map, access_map)
|
||||
|
||||
if scl_s is None or scl_tv is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# 2. Validar y obtener Nombre de Instancia
|
||||
instance_name = None
|
||||
if timer_instance_info and timer_instance_info.get("type") == "variable":
|
||||
instance_name = scl_instance_name
|
||||
elif timer_instance_info:
|
||||
print(f"Advertencia: Pin 'timer' de {instr_type} UID {instr_uid} conectado a algo inesperado: {timer_instance_info.get('type')}")
|
||||
instance_name = f"#TON_INSTANCE_{instr_uid}"
|
||||
else:
|
||||
instance_name = f"#TON_INSTANCE_{instr_uid}"
|
||||
print(f"Advertencia: No se encontró conexión al pin 'timer' para {instr_type} UID {instr_uid}. Usando placeholder '{instance_name}'. ¡Revisar x1.py y XML!")
|
||||
|
||||
# 3. Formatear entradas si son variables
|
||||
scl_s_formatted = format_variable_name(scl_s) if s_info and s_info.get("type") == "variable" else scl_s
|
||||
scl_tv_formatted = format_variable_name(scl_tv) if tv_info and tv_info.get("type") == "variable" else scl_tv
|
||||
|
||||
# 4. Generar la llamada SCL (TON usa IN, PT, Q, ET)
|
||||
scl_call = f"{instance_name}(IN := {scl_s_formatted}, PT := {scl_tv_formatted}); // TODO: Declarar {instance_name} : TON; en VAR_STAT o VAR"
|
||||
|
||||
instruction["scl"] = scl_call
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# 5. Actualizar scl_map para las salidas Q y RT (mapeado a ET de TON)
|
||||
map_key_q = (network_id, instr_uid, "q")
|
||||
scl_map[map_key_q] = f"{instance_name}.Q"
|
||||
map_key_rt = (network_id, instr_uid, "rt")
|
||||
scl_map[map_key_rt] = f"{instance_name}.ET"
|
||||
|
||||
return True
|
||||
|
||||
# --- NUEVO: Procesador de Agrupación (Refinado) ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el temporizador On-Delay (Sd -> TON)."""
|
||||
# Asumiendo que el tipo en el JSON es 'Sd'
|
||||
return {'type_name': 'sd', 'processor_func': process_sd, 'priority': 5}
|
|
@ -0,0 +1,91 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_se(instruction, network_id, scl_map, access_map, data):
|
||||
"""
|
||||
Genera SCL para Temporizador de Pulso (Se -> TP).
|
||||
Requiere datos de instancia (DB o STAT/TEMP).
|
||||
"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = "Se" # Tipo original LAD
|
||||
if instruction["type"].endswith(SCL_SUFFIX) or "_error" in instruction["type"]:
|
||||
return False
|
||||
|
||||
# 1. Obtener Inputs: s (start), tv (time value)
|
||||
# El pin 'r' (reset) no tiene equivalente directo en TP, se ignora aquí.
|
||||
s_info = instruction["inputs"].get("s")
|
||||
tv_info = instruction["inputs"].get("tv")
|
||||
timer_instance_info = instruction["inputs"].get("timer") # Esperando que x1 lo extraiga
|
||||
|
||||
scl_s = get_scl_representation(s_info, network_id, scl_map, access_map)
|
||||
scl_tv = get_scl_representation(tv_info, network_id, scl_map, access_map)
|
||||
# Obtenemos el nombre de la variable instancia, crucial!
|
||||
scl_instance_name = get_scl_representation(timer_instance_info, network_id, scl_map, access_map)
|
||||
|
||||
if scl_s is None or scl_tv is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# 2. Validar y obtener Nombre de Instancia
|
||||
instance_name = None
|
||||
if timer_instance_info and timer_instance_info.get("type") == "variable":
|
||||
instance_name = scl_instance_name # Ya debería estar formateado por get_scl_repr
|
||||
elif timer_instance_info: # Si está conectado pero no es variable directa? Raro.
|
||||
print(f"Advertencia: Pin 'timer' de {instr_type} UID {instr_uid} conectado a algo inesperado: {timer_instance_info.get('type')}")
|
||||
instance_name = f"#TP_INSTANCE_{instr_uid}" # Usar placeholder
|
||||
else: # Si no hay pin 'timer' conectado (no debería pasar si x1 funciona)
|
||||
instance_name = f"#TP_INSTANCE_{instr_uid}" # Usar placeholder
|
||||
print(f"Advertencia: No se encontró conexión al pin 'timer' para {instr_type} UID {instr_uid}. Usando placeholder '{instance_name}'. ¡Revisar x1.py y XML!")
|
||||
|
||||
# 3. Formatear entradas si son variables (aunque get_scl_representation ya debería hacerlo)
|
||||
scl_s_formatted = format_variable_name(scl_s) if s_info and s_info.get("type") == "variable" else scl_s
|
||||
scl_tv_formatted = format_variable_name(scl_tv) if tv_info and tv_info.get("type") == "variable" else scl_tv
|
||||
|
||||
# 4. Generar la llamada SCL (TP usa IN, PT, Q, ET)
|
||||
scl_call = f"{instance_name}(IN := {scl_s_formatted}, PT := {scl_tv_formatted}); // TODO: Declarar {instance_name} : TP; en VAR_STAT o VAR"
|
||||
|
||||
instruction["scl"] = scl_call
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# 5. Actualizar scl_map usando los nombres de pin ORIGINALES mapeados si existen
|
||||
output_pin_mapping_reverse = {v: k for k, v in instruction.get("_output_pin_mapping", {}).items()} # Necesitaríamos guardar el mapeo en x1
|
||||
|
||||
q_original_pin = "q" # Default
|
||||
rt_original_pin = "rt" # Default
|
||||
|
||||
# Intentar encontrar los pines originales si x1 guardó el mapeo (MEJORA NECESARIA en x1)
|
||||
# Por ahora, para SdCoil que mapeaba out->q, usaremos 'out' directamente
|
||||
if instruction.get("type") == "Se_scl" and instruction.get("original_type") == "SdCoil": # Necesitamos guardar original_type en x1
|
||||
q_original_pin = "out"
|
||||
# rt no existe en SdCoil
|
||||
|
||||
map_key_q = (network_id, instr_uid, q_original_pin)
|
||||
scl_map[map_key_q] = f"{instance_name}.Q"
|
||||
|
||||
if rt_original_pin: # Solo añadir rt si corresponde
|
||||
map_key_rt = (network_id, instr_uid, rt_original_pin)
|
||||
scl_map[map_key_rt] = f"{instance_name}.ET"
|
||||
|
||||
return True
|
||||
|
||||
# --- Procesador para Sd (On-Delay Timer -> TON SCL) ---
|
||||
|
||||
# --- Function code ends ---
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para el temporizador de Pulso (Se -> TP) y maneja SdCoil."""
|
||||
# Asumiendo que el tipo en el JSON es 'Se'
|
||||
# Y que SdCoil también se mapea aquí según el análisis previo
|
||||
return [
|
||||
{'type_name': 'se', 'processor_func': process_se, 'priority': 5},
|
||||
{'type_name': 'sdcoil', 'processor_func': process_se, 'priority': 5} # SdCoil también se procesa como TP
|
||||
]
|
|
@ -0,0 +1,70 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
||||
|
||||
|
||||
# TODO: Import necessary functions from processor_utils
|
||||
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
||||
# Or: import processors.processor_utils as utils
|
||||
|
||||
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
||||
SCL_SUFFIX = "_scl"
|
||||
|
||||
# --- Function code starts ---
|
||||
def process_timer(instruction, network_id, scl_map, access_map, data):
|
||||
"""
|
||||
Genera SCL para Temporizadores (TON, TOF).
|
||||
Requiere datos de instancia (DB o STAT).
|
||||
"""
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
instr_type = instruction["type"] # Será "TON" o "TOF"
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
||||
return False
|
||||
|
||||
# 1. Obtener Inputs
|
||||
in_info = instruction["inputs"].get("IN") # Entrada booleana
|
||||
pt_info = instruction["inputs"].get("PT") # Preset Time (Tipo TIME)
|
||||
scl_in = get_scl_representation(in_info, network_id, scl_map, access_map)
|
||||
scl_pt = get_scl_representation(pt_info, network_id, scl_map, access_map)
|
||||
|
||||
if scl_in is None or scl_pt is None:
|
||||
return False # Dependencias no listas
|
||||
|
||||
# 2. Obtener Nombre de Instancia (NECESITA MEJORA EN x1.py)
|
||||
instance_name = instruction.get("instance_db") # Reutilizar campo si x1 lo llena
|
||||
if not instance_name:
|
||||
# Generar placeholder si x1 no extrajo la instancia para Part
|
||||
instance_name = f"#TIMER_INSTANCE_{instr_uid}" # Placeholder para VAR_TEMP o VAR_STAT
|
||||
print(f"Advertencia: No se encontró instancia para {instr_type} UID {instr_uid}. Usando placeholder '{instance_name}'. Ajustar x1.py y declarar en x3.py.")
|
||||
else:
|
||||
instance_name = format_variable_name(instance_name) # Limpiar si viene de x1
|
||||
|
||||
# 3. Formatear entradas si son variables
|
||||
scl_in_formatted = format_variable_name(scl_in) if in_info and in_info.get("type") == "variable" else scl_in
|
||||
scl_pt_formatted = format_variable_name(scl_pt) if pt_info and pt_info.get("type") == "variable" else scl_pt
|
||||
|
||||
# 4. Generar la llamada SCL
|
||||
# Nota: Las salidas Q y ET se acceden directamente desde la instancia.
|
||||
scl_call = f"{instance_name}(IN := {scl_in_formatted}, PT := {scl_pt_formatted}); // TODO: Declarar {instance_name} : {instr_type}; en VAR_STAT o VAR"
|
||||
|
||||
instruction["scl"] = scl_call
|
||||
instruction["type"] = instr_type + SCL_SUFFIX
|
||||
|
||||
# 5. Actualizar scl_map para las salidas Q y ET
|
||||
map_key_q = (network_id, instr_uid, "Q")
|
||||
scl_map[map_key_q] = f"{instance_name}.Q"
|
||||
map_key_et = (network_id, instr_uid, "ET")
|
||||
scl_map[map_key_et] = f"{instance_name}.ET"
|
||||
# TON/TOF no tienen un pin ENO estándar en LAD/FBD que se mapee directamente
|
||||
|
||||
return True
|
||||
|
||||
# --- Processor Information Function ---
|
||||
def get_processor_info():
|
||||
"""Devuelve la información para los temporizadores TON y TOF (si se usan genéricamente)."""
|
||||
# Esta función manejaría tipos TON/TOF si aparecieran directamente en el JSON
|
||||
# y no fueran manejados por process_sd/process_se (que es lo más común desde LAD).
|
||||
# Incluir por si acaso o si la conversión inicial genera TON/TOF directamente.
|
||||
return [
|
||||
{'type_name': 'ton', 'processor_func': process_timer, 'priority': 5},
|
||||
{'type_name': 'tof', 'processor_func': process_timer, 'priority': 5}
|
||||
]
|
|
@ -0,0 +1,209 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# /processors/processor_utils.py
|
||||
# Procesador de utilidades para el procesamiento de archivos XML de Simatic
|
||||
import re
|
||||
|
||||
# --- Copia aquí las funciones auxiliares ---
|
||||
# get_scl_representation, format_variable_name,
|
||||
# generate_temp_var_name, get_target_scl_name
|
||||
# Asegúrate de que no dependen de variables globales de x2_process.py
|
||||
# (como 'data' o 'network_access_maps' - esas se pasarán como argumentos)
|
||||
|
||||
# Ejemplo de una función (asegúrate de copiar todas las necesarias)
|
||||
def format_variable_name(name):
|
||||
"""Limpia el nombre de la variable para SCL."""
|
||||
if not name:
|
||||
return "_INVALID_NAME_"
|
||||
if name.startswith('"') and name.endswith('"'):
|
||||
return name
|
||||
prefix = ""
|
||||
if name.startswith("#"):
|
||||
prefix = "#"
|
||||
name = name[1:]
|
||||
if name and name[0].isdigit():
|
||||
name = "_" + name
|
||||
name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
|
||||
return prefix + name
|
||||
|
||||
# --- Helper Functions ---
|
||||
# (get_scl_representation, format_variable_name, generate_temp_var_name, get_target_scl_name - sin cambios)
|
||||
def get_scl_representation(source_info, network_id, scl_map, access_map):
|
||||
if not source_info:
|
||||
return None
|
||||
if isinstance(source_info, list):
|
||||
scl_parts = []
|
||||
all_resolved = True
|
||||
for sub_source in source_info:
|
||||
sub_scl = get_scl_representation(
|
||||
sub_source, network_id, scl_map, access_map
|
||||
)
|
||||
if sub_scl is None:
|
||||
all_resolved = False
|
||||
break
|
||||
if (
|
||||
sub_scl in ["TRUE", "FALSE"]
|
||||
or (sub_scl.startswith('"') and sub_scl.endswith('"'))
|
||||
or sub_scl.isdigit()
|
||||
or (sub_scl.startswith("(") and sub_scl.endswith(")"))
|
||||
):
|
||||
scl_parts.append(sub_scl)
|
||||
else:
|
||||
scl_parts.append(f"({sub_scl})")
|
||||
return (
|
||||
" OR ".join(scl_parts)
|
||||
if len(scl_parts) > 1
|
||||
else (scl_parts[0] if scl_parts else "FALSE") if all_resolved else None
|
||||
)
|
||||
source_type = source_info.get("type")
|
||||
if source_type == "powerrail":
|
||||
return "TRUE"
|
||||
elif source_type == "variable":
|
||||
name = source_info.get("name")
|
||||
# Asegurar que los nombres de variables se formatean correctamente aquí también
|
||||
return (
|
||||
format_variable_name(name)
|
||||
if name
|
||||
else f"_ERR_VAR_NO_NAME_{source_info.get('uid')}_"
|
||||
)
|
||||
elif source_type == "constant":
|
||||
dtype = str(source_info.get("datatype", "")).upper()
|
||||
value = source_info.get("value")
|
||||
try:
|
||||
if dtype == "BOOL":
|
||||
return str(value).upper()
|
||||
elif dtype in [
|
||||
"INT",
|
||||
"DINT",
|
||||
"SINT",
|
||||
"USINT",
|
||||
"UINT",
|
||||
"UDINT",
|
||||
"LINT",
|
||||
"ULINT",
|
||||
"WORD",
|
||||
"DWORD",
|
||||
"LWORD",
|
||||
"BYTE",
|
||||
]:
|
||||
return str(value)
|
||||
elif dtype in ["REAL", "LREAL"]:
|
||||
s_val = str(value)
|
||||
return s_val if "." in s_val or "e" in s_val.lower() else s_val + ".0"
|
||||
elif dtype == "STRING":
|
||||
# Escapar comillas simples dentro del string si es necesario
|
||||
str_val = str(value).replace("'", "''")
|
||||
return f"'{str_val}'"
|
||||
elif dtype == "TYPEDCONSTANT":
|
||||
# Podría necesitar formateo específico basado en el tipo real
|
||||
return str(value)
|
||||
else:
|
||||
# Otros tipos (TIME, DATE, etc.) - devolver como string por ahora
|
||||
str_val = str(value).replace("'", "''")
|
||||
return f"'{str_val}'"
|
||||
except Exception as e:
|
||||
print(f"Advertencia: Error formateando constante {source_info}: {e}")
|
||||
return f"_ERR_CONST_FORMAT_{source_info.get('uid')}_"
|
||||
elif source_type == "connection":
|
||||
map_key = (
|
||||
network_id,
|
||||
source_info.get("source_instruction_uid"),
|
||||
source_info.get("source_pin"),
|
||||
)
|
||||
return scl_map.get(map_key)
|
||||
elif source_type == "unknown_source":
|
||||
print(
|
||||
f"Advertencia: Refiriendo a fuente desconocida UID: {source_info.get('uid')}"
|
||||
)
|
||||
return f"_ERR_UNKNOWN_SRC_{source_info.get('uid')}_"
|
||||
else:
|
||||
print(f"Advertencia: Tipo de fuente desconocido: {source_info}")
|
||||
return f"_ERR_INVALID_SRC_TYPE_"
|
||||
|
||||
def format_variable_name(name):
|
||||
"""Limpia el nombre de la variable para SCL."""
|
||||
if not name:
|
||||
return "_INVALID_NAME_"
|
||||
|
||||
# Si ya está entre comillas dobles, asumimos que es un nombre complejo (ej. "DB"."Variable")
|
||||
# y lo devolvemos tal cual para SCL.
|
||||
if name.startswith('"') and name.endswith('"'):
|
||||
# Podríamos añadir validación extra aquí si fuera necesario
|
||||
return name
|
||||
|
||||
# Si no tiene comillas, es un nombre simple (ej. Tag_1, #tempVar)
|
||||
# Reemplazar caracteres no válidos (excepto '_') por '_'
|
||||
# Permitir '#' al inicio para variables temporales
|
||||
prefix = ""
|
||||
if name.startswith("#"):
|
||||
prefix = "#"
|
||||
name = name[1:]
|
||||
|
||||
# Permitir letras, números y guiones bajos. Reemplazar el resto.
|
||||
# Asegurarse de que no empiece con número (después del # si existe)
|
||||
if name and name[0].isdigit():
|
||||
name = "_" + name
|
||||
# Reemplazar caracteres no válidos
|
||||
name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
|
||||
|
||||
return prefix + name
|
||||
|
||||
def generate_temp_var_name(network_id, instr_uid, pin_name):
|
||||
net_id_clean = str(network_id).replace("-", "_")
|
||||
instr_uid_clean = str(instr_uid).replace("-", "_")
|
||||
pin_name_clean = str(pin_name).replace("-", "_").lower()
|
||||
# Usar # para variables temporales SCL estándar
|
||||
return f"#_temp_{net_id_clean}_{instr_uid_clean}_{pin_name_clean}"
|
||||
|
||||
def get_target_scl_name(instruction, output_pin_name, network_id, default_to_temp=True):
|
||||
instr_uid = instruction["instruction_uid"]
|
||||
output_pin_data = instruction["outputs"].get(output_pin_name)
|
||||
target_scl = None
|
||||
if (
|
||||
output_pin_data
|
||||
and isinstance(output_pin_data, list)
|
||||
and len(output_pin_data) == 1
|
||||
):
|
||||
dest_access = output_pin_data[0]
|
||||
if dest_access.get("type") == "variable":
|
||||
target_scl = dest_access.get("name")
|
||||
if target_scl:
|
||||
target_scl = format_variable_name(target_scl) # Formatear nombre
|
||||
else:
|
||||
print(
|
||||
f"Error: Var destino {instr_uid}.{output_pin_name} sin nombre (UID: {dest_access.get('uid')}). {'Usando temp.' if default_to_temp else 'Ignorando.'}"
|
||||
)
|
||||
target_scl = (
|
||||
generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
if default_to_temp
|
||||
else None
|
||||
)
|
||||
elif dest_access.get("type") == "constant":
|
||||
print(
|
||||
f"Advertencia: Instr {instr_uid} escribe en const UID {dest_access.get('uid')}. {'Usando temp.' if default_to_temp else 'Ignorando.'}"
|
||||
)
|
||||
target_scl = (
|
||||
generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
if default_to_temp
|
||||
else None
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"Advertencia: Destino {instr_uid}.{output_pin_name} no es var/const: {dest_access.get('type')}. {'Usando temp.' if default_to_temp else 'Ignorando.'}"
|
||||
)
|
||||
target_scl = (
|
||||
generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
if default_to_temp
|
||||
else None
|
||||
)
|
||||
elif default_to_temp:
|
||||
target_scl = generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
|
||||
# Si target_scl sigue siendo None y no se debe usar temp, devolver None
|
||||
if target_scl is None and not default_to_temp:
|
||||
return None
|
||||
|
||||
# Si target_scl es None pero sí se permite temp, generar uno ahora
|
||||
if target_scl is None and default_to_temp:
|
||||
target_scl = generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
|
||||
return target_scl
|
|
@ -0,0 +1,145 @@
|
|||
import argparse
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import locale
|
||||
import glob # <--- Importar glob para buscar archivos
|
||||
|
||||
# (Función get_console_encoding y variable CONSOLE_ENCODING como en la respuesta anterior)
|
||||
def get_console_encoding():
|
||||
"""Obtiene la codificación preferida de la consola, con fallback."""
|
||||
try:
|
||||
return locale.getpreferredencoding(False)
|
||||
except Exception:
|
||||
return 'cp1252'
|
||||
|
||||
CONSOLE_ENCODING = get_console_encoding()
|
||||
# Descomenta la siguiente línea si quieres ver la codificación detectada:
|
||||
# print(f"Detected console encoding: {CONSOLE_ENCODING}")
|
||||
|
||||
# (Función run_script como en la respuesta anterior, usando CONSOLE_ENCODING)
|
||||
def run_script(script_name, xml_arg):
|
||||
"""Runs a given script with the specified XML file argument."""
|
||||
script_path = os.path.join(os.path.dirname(__file__), script_name)
|
||||
command = [sys.executable, script_path, xml_arg]
|
||||
print(f"\n--- Running {script_name} with argument: {xml_arg} ---")
|
||||
try:
|
||||
result = subprocess.run(command,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding=CONSOLE_ENCODING,
|
||||
errors='replace') # 'replace' para evitar errores
|
||||
|
||||
# Imprimir stdout y stderr
|
||||
# Eliminar saltos de línea extra al final si existen
|
||||
stdout_clean = result.stdout.strip()
|
||||
stderr_clean = result.stderr.strip()
|
||||
if stdout_clean:
|
||||
print(stdout_clean)
|
||||
if stderr_clean:
|
||||
print("--- Stderr ---")
|
||||
print(stderr_clean)
|
||||
print("--------------")
|
||||
print(f"--- {script_name} finished successfully ---")
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
print(f"Error: Script '{script_path}' not found.")
|
||||
return False
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error running {script_name}:")
|
||||
print(f"Return code: {e.returncode}")
|
||||
stdout_decoded = e.stdout.decode(CONSOLE_ENCODING, errors='replace').strip() if isinstance(e.stdout, bytes) else (e.stdout or "").strip()
|
||||
stderr_decoded = e.stderr.decode(CONSOLE_ENCODING, errors='replace').strip() if isinstance(e.stderr, bytes) else (e.stderr or "").strip()
|
||||
if stdout_decoded:
|
||||
print("--- Stdout ---")
|
||||
print(stdout_decoded)
|
||||
if stderr_decoded:
|
||||
print("--- Stderr ---")
|
||||
print(stderr_decoded)
|
||||
print("--------------")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred while running {script_name}: {e}")
|
||||
return False
|
||||
|
||||
# --- NUEVA FUNCIÓN PARA SELECCIONAR ARCHIVO ---
|
||||
def select_xml_file():
|
||||
"""Busca archivos .xml, los lista y pide al usuario que elija uno."""
|
||||
print("No XML file specified. Searching for XML files in current directory...")
|
||||
# Buscar archivos .xml en el directorio actual (.)
|
||||
xml_files = sorted(glob.glob('*.xml')) # sorted para orden alfabético
|
||||
|
||||
if not xml_files:
|
||||
print("Error: No .xml files found in the current directory.")
|
||||
sys.exit(1)
|
||||
|
||||
print("\nAvailable XML files:")
|
||||
for i, filename in enumerate(xml_files, start=1):
|
||||
print(f" {i}: {filename}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
choice = input(f"Enter the number of the file to process (1-{len(xml_files)}): ")
|
||||
choice_num = int(choice)
|
||||
if 1 <= choice_num <= len(xml_files):
|
||||
selected_file = xml_files[choice_num - 1]
|
||||
print(f"Selected: {selected_file}")
|
||||
return selected_file
|
||||
else:
|
||||
print("Invalid choice. Please enter a number from the list.")
|
||||
except ValueError:
|
||||
print("Invalid input. Please enter a number.")
|
||||
except EOFError: # Manejar si la entrada se cierra inesperadamente
|
||||
print("\nSelection cancelled.")
|
||||
sys.exit(1)
|
||||
# --- FIN NUEVA FUNCIÓN ---
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
xml_filename = None
|
||||
|
||||
# Comprobar si se pasó un argumento de línea de comandos
|
||||
# sys.argv[0] es el nombre del script, sys.argv[1] sería el primer argumento
|
||||
if len(sys.argv) > 1:
|
||||
# Si hay argumentos, usar argparse para parsearlo (permite -h, etc.)
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Run the Simatic XML processing pipeline."
|
||||
)
|
||||
parser.add_argument(
|
||||
"xml_file",
|
||||
# Ya no necesitamos nargs='?' ni default aquí porque sabemos que hay un argumento
|
||||
help="Path to the XML file to process.",
|
||||
)
|
||||
# Parsear solo los argumentos conocidos, ignorar extras si los hubiera
|
||||
args, unknown = parser.parse_known_args()
|
||||
xml_filename = args.xml_file
|
||||
print(f"XML file specified via argument: {xml_filename}")
|
||||
else:
|
||||
# Si no hay argumentos, llamar a la función interactiva
|
||||
xml_filename = select_xml_file()
|
||||
|
||||
# --- El resto del script continúa igual, usando xml_filename ---
|
||||
|
||||
# Verificar si el archivo XML de entrada (seleccionado o pasado) existe
|
||||
if not os.path.exists(xml_filename):
|
||||
print(f"Error: Selected or specified XML file not found: {xml_filename}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\nStarting pipeline for: {xml_filename}")
|
||||
|
||||
# Run scripts sequentially (asegúrate que los nombres son correctos)
|
||||
script1 = "x1_to_json.py"
|
||||
script2 = "x2_process.py"
|
||||
script3 = "x3_generate_scl.py"
|
||||
|
||||
if run_script(script1, xml_filename):
|
||||
if run_script(script2, xml_filename):
|
||||
if run_script(script3, xml_filename):
|
||||
print("\nPipeline completed successfully.")
|
||||
else:
|
||||
print("\nPipeline failed at script:", script3)
|
||||
else:
|
||||
print("\nPipeline failed at script:", script2)
|
||||
else:
|
||||
print("\nPipeline failed at script:", script1)
|
1148
x1_to_json.py
1148
x1_to_json.py
File diff suppressed because it is too large
Load Diff
1475
x2_process.py
1475
x2_process.py
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,7 @@
|
|||
import json
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
|
||||
# --- Helper Functions ---
|
||||
|
||||
|
@ -155,32 +156,73 @@ def generate_scl(processed_json_filepath, output_scl_filepath):
|
|||
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}")
|
||||
# Obtener lenguaje original de la red, default a LAD si no está
|
||||
network_lang = network.get('language', 'LAD')
|
||||
|
||||
scl_output.append(f" // Network {i+1}: {network_title} (Original Language: {network_lang})")
|
||||
if network_comment:
|
||||
# Añadir comentario de red indentado
|
||||
for line in network_comment.splitlines():
|
||||
scl_output.append(f" // {line}")
|
||||
scl_output.append("") # Línea en blanco antes del código de la red
|
||||
|
||||
network_has_code = False
|
||||
# Iterar sobre la 'logica' de la red
|
||||
for instruction in network.get('logic', []):
|
||||
instruction_type = instruction.get("type", "")
|
||||
scl_code = instruction.get('scl')
|
||||
if scl_code:
|
||||
network_has_code = True
|
||||
# Indentar y añadir el código SCL de la instrucción
|
||||
# Quitar comentarios "// RLO updated..." o "// Comparison..."
|
||||
# ya que el código SCL resultante es la representación final.
|
||||
# Mantener comentarios de PBox por claridad.
|
||||
is_rlo_update_comment = scl_code.strip().startswith("// RLO updated")
|
||||
is_comparison_comment = scl_code.strip().startswith("// Comparison")
|
||||
is_logic_o_comment = scl_code.strip().startswith("// Logic O")
|
||||
|
||||
if not (is_rlo_update_comment or is_comparison_comment or is_logic_o_comment) or "PBox" in scl_code :
|
||||
for line in scl_code.splitlines():
|
||||
scl_output.append(f" {line}") # Indentación de 2 espacios
|
||||
# --- INICIO: Manejar RAW_SCL_CHUNK y otros tipos ---
|
||||
if instruction_type == "RAW_SCL_CHUNK" and scl_code:
|
||||
network_has_code = True
|
||||
# Imprimir el SCL reconstruido directamente
|
||||
for line in scl_code.splitlines():
|
||||
scl_output.append(f" {line}") # Añadir indentación
|
||||
elif instruction_type == "UNSUPPORTED_LANG" and scl_code:
|
||||
network_has_code = True
|
||||
# Imprimir comentario para lenguajes no soportados
|
||||
for line in scl_code.splitlines():
|
||||
scl_output.append(f" {line}")
|
||||
elif instruction_type.endswith("_scl") and scl_code:
|
||||
# Código SCL generado por x2_process.py para LAD/FBD
|
||||
if instruction.get("grouped", False): # Ignorar si fue agrupado
|
||||
continue
|
||||
|
||||
# Lógica mejorada para omitir comentarios internos si no aportan
|
||||
lines = scl_code.splitlines()
|
||||
is_internal_comment_only = (len(lines) == 1 and
|
||||
(lines[0].strip().startswith("// RLO") or
|
||||
lines[0].strip().startswith("// Comparison") or
|
||||
lines[0].strip().startswith("// Logic O") or
|
||||
lines[0].strip().startswith("// Logic included in grouped IF") or # Usar GROUPED_COMMENT si lo importas
|
||||
lines[0].strip().startswith("// P_TRIG") or
|
||||
lines[0].strip().startswith("// N_TRIG") ))
|
||||
|
||||
if not is_internal_comment_only:
|
||||
network_has_code = True
|
||||
for line in lines:
|
||||
clean_line = line.strip()
|
||||
# Omitir comentarios autogenerados específicos
|
||||
if not (clean_line.startswith("// RLO:") or \
|
||||
clean_line.startswith("// Comparison") or \
|
||||
clean_line.startswith("// Logic O") or \
|
||||
clean_line == "// Logic included in grouped IF" or \
|
||||
clean_line.startswith("// P_TRIG(") or \
|
||||
clean_line.startswith("// N_TRIG(")):
|
||||
scl_output.append(f" {line}") # Indentación
|
||||
# Ignorar instrucciones no procesadas (sin _scl) o con error
|
||||
# elif "_error" in instruction_type:
|
||||
# scl_output.append(f" // Error processing instruction {instruction.get('instruction_uid')}: {scl_code}")
|
||||
# network_has_code = True
|
||||
|
||||
|
||||
# --- FIN: Manejar RAW_SCL_CHUNK y otros tipos ---
|
||||
|
||||
if network_has_code:
|
||||
scl_output.append("") # Añadir línea en blanco después del código de la red
|
||||
scl_output.append("") # Añadir línea en blanco después del código de la red si hubo algo
|
||||
else:
|
||||
# Añadir comentario si la red estaba vacía o no generó código imprimible
|
||||
scl_output.append(f" // Network did not produce printable SCL code.")
|
||||
scl_output.append("")
|
||||
|
||||
scl_output.append("END_FUNCTION_BLOCK")
|
||||
|
||||
|
@ -196,13 +238,35 @@ def generate_scl(processed_json_filepath, output_scl_filepath):
|
|||
|
||||
# --- Ejecución ---
|
||||
if __name__ == "__main__":
|
||||
# Imports necesarios solo para la ejecución como script principal
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
xml_file = "TestLAD.xml" # CAMBIAR AL NUEVO ARCHIVO XML
|
||||
input_json_file = xml_file.replace(
|
||||
".xml", "_simplified_processed.json"
|
||||
) # Nombre de salida dinámico
|
||||
output_scl_file = input_json_file.replace(
|
||||
".json", ".scl"
|
||||
) # Nombre de salida dinámico
|
||||
parser = argparse.ArgumentParser(description="Generate final SCL file from processed JSON.")
|
||||
# Acepta el nombre del XML original como referencia para derivar nombres
|
||||
parser.add_argument(
|
||||
"source_xml_filepath",
|
||||
nargs="?",
|
||||
default="TestLAD.xml",
|
||||
help="Path to the original source XML file (used to derive input/output names, default: TestLAD.xml)"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
generate_scl(input_json_file, output_scl_file)
|
||||
# Derivar nombres de archivos de entrada y salida
|
||||
xml_filename_base = os.path.splitext(os.path.basename(args.source_xml_filepath))[0]
|
||||
input_dir = os.path.dirname(args.source_xml_filepath) # Directorio del XML original
|
||||
|
||||
# Nombre del JSON procesado (entrada para este script)
|
||||
input_json_file = os.path.join(input_dir, f"{xml_filename_base}_simplified_processed.json")
|
||||
# Nombre del SCL final (salida de este script)
|
||||
output_scl_file = os.path.join(input_dir, f"{xml_filename_base}_simplified_processed.scl")
|
||||
|
||||
# Verificar si el archivo JSON procesado de entrada existe
|
||||
if not os.path.exists(input_json_file):
|
||||
print(f"Error: Processed JSON file not found: '{input_json_file}'")
|
||||
print(f"Ensure 'x2_process.py' ran successfully for '{args.source_xml_filepath}'.")
|
||||
sys.exit(1) # Salir si el archivo de entrada no existe
|
||||
else:
|
||||
# Llamar a la función principal con los nombres derivados
|
||||
generate_scl(input_json_file, output_scl_file)
|
Loading…
Reference in New Issue