Add S7 data block and JSON documentation generator

- Created a new data block file `reconstructed_s7_source_stat.txt` containing structured data for HMI Blender parameters.
- Implemented a Python script `x5.py` to generate Markdown documentation from parsed S7 JSON data, including formatting for UDTs and DBs.
- The script includes functions for formatting data types, offsets, and generating tables for members, as well as handling current values and comments.
This commit is contained in:
Miguel 2025-05-17 14:48:28 +02:00
parent de5134920d
commit 884166b60e
9 changed files with 6482 additions and 898 deletions

View File

@ -2,253 +2,254 @@
| Address | Name | Type | Initial Value | Actual Value | Comment | | Address | Name | Type | Initial Value | Actual Value | Comment |
|---|---|---|---|---|---| |---|---|---|---|---|---|
| 0.0 | Processor_Options.Blender_OPT._ModelNum | INT | 6 | 6 | | | 0.0 | STAT0.STAT1.STAT2 | INT | 6 | 6 | |
| 2.0 | Processor_Options.Blender_OPT._CO2_Offset | REAL | 4.500000e-01 | 4.500000e-01 | | | 2.0 | STAT0.STAT1.STAT3 | REAL | 2.000000e-01 | 4.500000e-01 | |
| 6.0 | Processor_Options.Blender_OPT._MaxSyrDeltaBrix | REAL | 8.000000e-01 | 8.000000e-01 | | | 6.0 | STAT0.STAT1.STAT4 | REAL | 8.000000e-01 | 8.000000e-01 | |
| 10.0 | Processor_Options.Blender_OPT._BrixMeter | BOOL | TRUE | TRUE | | | 10.0 | STAT0.STAT1.STAT5 | BOOL | TRUE | TRUE | |
| 10.1 | Processor_Options.Blender_OPT.Spare101 | BOOL | | FALSE | | | 10.1 | STAT0.STAT1.STAT6 | BOOL | | FALSE | |
| 10.2 | Processor_Options.Blender_OPT._TrackH2OEnable | BOOL | | FALSE | | | 10.2 | STAT0.STAT1.STAT7 | BOOL | | FALSE | |
| 10.3 | Processor_Options.Blender_OPT._PAmPDSType | BOOL | | FALSE | 0)Cobrix 2000 1)Carbo 2000 | | 10.3 | STAT0.STAT1.STAT8 | BOOL | | FALSE | |
| 10.4 | Processor_Options.Blender_OPT._HistoricalTrends | BOOL | TRUE | TRUE | 0)Not Present 1)Present | | 10.4 | STAT0.STAT1.STAT9 | BOOL | | TRUE | |
| 10.5 | Processor_Options.Blender_OPT._PowerMeter | BOOL | | FALSE | 0)Not Present 1)Present | | 10.5 | STAT0.STAT1.STAT10 | BOOL | | FALSE | |
| 10.6 | Processor_Options.Blender_OPT._Report | BOOL | TRUE | TRUE | 0)Not Present 1)Present | | 10.6 | STAT0.STAT1.STAT11 | BOOL | TRUE | TRUE | |
| 10.7 | Processor_Options.Blender_OPT._Balaiage | BOOL | | FALSE | | | 10.7 | STAT0.STAT1.STAT12 | BOOL | | FALSE | |
| 11.0 | Processor_Options.Blender_OPT._Valves_FullFeedback | BOOL | TRUE | TRUE | Valves control Full feedback | | 11.0 | STAT0.STAT1.STAT13 | BOOL | TRUE | TRUE | |
| 11.1 | Processor_Options.Blender_OPT._Valves_SingleFeedback | BOOL | | FALSE | Valves control Single feedback | | 11.1 | STAT0.STAT1.STAT14 | BOOL | | FALSE | |
| 11.2 | Processor_Options.Blender_OPT._PumpsSafetySwitches | BOOL | | FALSE | Pumps with Safety Switches | | 11.2 | STAT0.STAT1.STAT15 | BOOL | | FALSE | |
| 11.3 | Processor_Options.Blender_OPT._SurgeProtectionAct | BOOL | | FALSE | | | 11.3 | STAT0.STAT1.STAT16 | BOOL | | FALSE | |
| 11.4 | Processor_Options.Blender_OPT._DBC_Type | BOOL | | FALSE | 0) Deox,Carbo,Blend 1)Deox,Blend,Carbo | | 11.4 | STAT0.STAT1.STAT17 | BOOL | | FALSE | |
| 11.5 | Processor_Options.Blender_OPT._CO2InletMeter | BOOL | TRUE | TRUE | 0)Not Present 1)Present | | 11.5 | STAT0.STAT1.STAT18 | BOOL | TRUE | TRUE | |
| 11.6 | Processor_Options.Blender_OPT._ProductO2Meter | BOOL | | FALSE | 0)Not Present 1)Present | | 11.6 | STAT0.STAT1.STAT19 | BOOL | | FALSE | |
| 11.7 | Processor_Options.Blender_OPT._CopressedAirInletMeter | BOOL | | FALSE | 0)Not Present 1)Present | | 11.7 | STAT0.STAT1.STAT20 | BOOL | | FALSE | |
| 12.0 | Processor_Options.Blender_OPT._MeterType | INT | 6 | 6 | 1)Maselli 2)AntoonPaar 3)4-20mA 4)UC05 UR22 5)mPDSPA 6)MR02 | | 12.0 | STAT0.STAT1.STAT21 | INT | 6 | 6 | |
| 14.0 | Processor_Options.Blender_OPT._MeterReceiveOnly | BOOL | | FALSE | | | 14.0 | STAT0.STAT1.STAT22 | BOOL | | FALSE | |
| 14.1 | Processor_Options.Blender_OPT._SyrBrixMeter | BOOL | | FALSE | | | 14.1 | STAT0.STAT1.STAT23 | BOOL | | FALSE | |
| 14.2 | Processor_Options.Blender_OPT._Flooding_Start_Up | BOOL | | FALSE | 0)Not Selected 1)Selected | | 14.2 | STAT0.STAT1.STAT24 | BOOL | | FALSE | |
| 14.3 | Processor_Options.Blender_OPT._FastChangeOverEnabled | BOOL | TRUE | TRUE | | | 14.3 | STAT0.STAT1.STAT25 | BOOL | | TRUE | |
| 14.4 | Processor_Options.Blender_OPT._WaterInletMeter | BOOL | | FALSE | 0)Not Present 1)Present | | 14.4 | STAT0.STAT1.STAT26 | BOOL | | FALSE | |
| 14.5 | Processor_Options.Blender_OPT._BlendFillSystem | BOOL | TRUE | TRUE | | | 14.5 | STAT0.STAT1.STAT27 | BOOL | TRUE | TRUE | |
| 14.6 | Processor_Options.Blender_OPT._TrackFillerSpeed | BOOL | TRUE | TRUE | | | 14.6 | STAT0.STAT1.STAT28 | BOOL | TRUE | TRUE | |
| 16.0 | Processor_Options.Blender_OPT._SignalExchange | INT | 1 | 1 | FILLER - 0= Hardwire; 1= Ethernet | | 16.0 | STAT0.STAT1.STAT29 | INT | 1 | 1 | |
| 18.0 | Processor_Options.Blender_OPT._CoolerPresent | BOOL | TRUE | TRUE | | | 18.0 | STAT0.STAT1.STAT30 | BOOL | TRUE | TRUE | |
| 20.0 | Processor_Options.Blender_OPT._CoolerControl | INT | 4 | 4 | 0)External 1)Water 2)Product 3)Water+Product-2 Ctrl 4)Water+Product-1 Ctrl | | 20.0 | STAT0.STAT1.STAT31 | INT | 4 | 4 | |
| 22.0 | Processor_Options.Blender_OPT._CoolerType | INT | | 0 | 0)Glycol 1)Ammonia | | 22.0 | STAT0.STAT1.STAT32 | INT | | 0 | |
| 24.0 | Processor_Options.Blender_OPT._LocalCIP | BOOL | | FALSE | | | 24.0 | STAT0.STAT1.STAT33 | BOOL | | FALSE | |
| 24.1 | Processor_Options.Blender_OPT._ICS_CustomerHotWater | BOOL | | FALSE | 0)No Hot Water from Customer 1)Hot Water from Customer Available | | 24.1 | STAT0.STAT1.STAT34 | BOOL | | FALSE | |
| 24.2 | Processor_Options.Blender_OPT._ICS_CustomerChemRecov | BOOL | | FALSE | 0)No Customer's Chemicals Recovery 1)Customer's Chemicals Recovery Available | | 24.2 | STAT0.STAT1.STAT35 | BOOL | | FALSE | |
| 24.3 | Processor_Options.Blender_OPT._CIPSignalExchange | BOOL | | FALSE | CIP - 0= Hardwire; 1= Ethernet | | 24.3 | STAT0.STAT1.STAT36 | BOOL | | FALSE | |
| 24.4 | Processor_Options.Blender_OPT._ICS_CustomerChemicals | BOOL | | FALSE | 0)Chemicals from ICS 1)Chemicals from Customer | | 24.4 | STAT0.STAT1.STAT37 | BOOL | | FALSE | |
| 24.5 | Processor_Options.Blender_OPT._CarboPresent | BOOL | TRUE | TRUE | | | 24.5 | STAT0.STAT1.STAT38 | BOOL | TRUE | TRUE | |
| 24.6 | Processor_Options.Blender_OPT._InverterSyrupPumpPPP302 | BOOL | | FALSE | 0)Not Present 1)Present | | 24.6 | STAT0.STAT1.STAT39 | BOOL | | FALSE | |
| 24.7 | Processor_Options.Blender_OPT._InverterWaterPumpPPN301 | BOOL | | FALSE | 0)Not Present 1)Present | | 24.7 | STAT0.STAT1.STAT40 | BOOL | | FALSE | |
| 25.0 | Processor_Options.Blender_OPT._DoubleDeair | BOOL | TRUE | TRUE | | | 25.0 | STAT0.STAT1.STAT41 | BOOL | TRUE | TRUE | |
| 25.1 | Processor_Options.Blender_OPT._DeairPreMixed | BOOL | | FALSE | Deox Premixed Inlet | | 25.1 | STAT0.STAT1.STAT42 | BOOL | | FALSE | |
| 25.2 | Processor_Options.Blender_OPT._Deaireation | BOOL | TRUE | TRUE | 0)SAG 1)SAE/SAF | | 25.2 | STAT0.STAT1.STAT43 | BOOL | TRUE | TRUE | |
| 25.3 | Processor_Options.Blender_OPT._StillWaterByPass | BOOL | | FALSE | | | 25.3 | STAT0.STAT1.STAT44 | BOOL | | FALSE | |
| 25.4 | Processor_Options.Blender_OPT._ManifoldSetting | BOOL | TRUE | TRUE | 0)Manual 1)Automatic | | 25.4 | STAT0.STAT1.STAT45 | BOOL | TRUE | TRUE | |
| 25.5 | Processor_Options.Blender_OPT._InverterProdPumpPPM303 | BOOL | | FALSE | | | 25.5 | STAT0.STAT1.STAT46 | BOOL | | FALSE | |
| 25.6 | Processor_Options.Blender_OPT._SidelCip | BOOL | | FALSE | | | 25.6 | STAT0.STAT1.STAT47 | BOOL | | FALSE | |
| 25.7 | Processor_Options.Blender_OPT._EthernetCom_CpuPN_CP | BOOL | TRUE | TRUE | 0)Comunication with CP 1)Comunication with CPU PN | | 25.7 | STAT0.STAT1.STAT48 | BOOL | TRUE | TRUE | |
| 26.0 | Processor_Options.Blender_OPT._2ndOutlet | INT | | 0 | 0)No 2nd Outlet 1)2nd Outlet No Standalone 2)2nd Outlet Standalone | | 26.0 | STAT0.STAT1.STAT49 | INT | | 0 | |
| 28.0 | Processor_Options.Blender_OPT._Promass | INT | 2 | 2 | | | 28.0 | STAT0.STAT1.STAT50 | INT | 2 | 2 | |
| 30.0 | Processor_Options.Blender_OPT._WaterPromass | BOOL | TRUE | TRUE | 0)Promag 1)Promass | | 30.0 | STAT0.STAT1.STAT51 | BOOL | TRUE | TRUE | |
| 30.1 | Processor_Options.Blender_OPT._ProductConductimeter | BOOL | | FALSE | | | 30.1 | STAT0.STAT1.STAT52 | BOOL | | FALSE | |
| 30.2 | Processor_Options.Blender_OPT._ICS_CustomerH2ORecov | BOOL | | FALSE | 0)No Customer's H2O Recovery 1)Customer's H2O Recovery Available | | 30.2 | STAT0.STAT1.STAT53 | BOOL | | FALSE | |
| 30.3 | Processor_Options.Blender_OPT.Spare303 | BOOL | | FALSE | | | 30.3 | STAT0.STAT1.STAT54 | BOOL | | FALSE | |
| 30.4 | Processor_Options.Blender_OPT._CO2_GAS2_Injection | BOOL | | FALSE | 0)Only CO2 Injection 1)GAS2 Injection | | 30.4 | STAT0.STAT1.STAT55 | BOOL | | FALSE | |
| 30.5 | Processor_Options.Blender_OPT._InverterVacuuPumpPPN304 | BOOL | | FALSE | 0)Not Present 1)Present | | 30.5 | STAT0.STAT1.STAT56 | BOOL | | FALSE | |
| 30.6 | Processor_Options.Blender_OPT._InverterBoostPumpPPM307 | BOOL | | FALSE | 0)Not Present 1)Present | | 30.6 | STAT0.STAT1.STAT57 | BOOL | | FALSE | |
| 30.7 | Processor_Options.Blender_OPT._RunOut_Water | BOOL | TRUE | TRUE | 0)Syrup Runout without Water 1)Syrup runout with Water pushing | | 30.7 | STAT0.STAT1.STAT58 | BOOL | TRUE | TRUE | |
| 31.0 | Processor_Options.Blender_OPT._FlowMeterType | BOOL | | TRUE | 0)Endrees Hauser -- 1)Micromotion | | 31.0 | STAT0.STAT1.STAT59 | BOOL | | TRUE | |
| 31.1 | Processor_Options.Blender_OPT._SidelFiller | BOOL | | FALSE | 0)Filler Simonazzi -- 1)Filler Sidel Filling | | 31.1 | STAT0.STAT1.STAT60 | BOOL | | FALSE | |
| 31.2 | Processor_Options.Blender_OPT._Simulation | BOOL | | FALSE | | | 31.2 | STAT0.STAT1.STAT61 | BOOL | | FALSE | |
| 31.3 | Processor_Options.Blender_OPT._ProductCoolingCTRL | BOOL | | FALSE | 0)none 1) TTM307 | | 31.3 | STAT0.STAT1.STAT62 | BOOL | | FALSE | |
| 31.4 | Processor_Options.Blender_OPT._ChillerCTRL | BOOL | | FALSE | Chiller Pressure Cross Control | | 31.4 | STAT0.STAT1.STAT63 | BOOL | | FALSE | |
| 31.5 | Processor_Options.Blender_OPT._CO2_SterileFilter | BOOL | TRUE | TRUE | CO2 Inlet with Steril Filter | | 31.5 | STAT0.STAT1.STAT64 | BOOL | TRUE | TRUE | |
| 31.6 | Processor_Options.Blender_OPT._InverterRecirPumpPPM306 | BOOL | | FALSE | 0)Not Present 1)Present | | 31.6 | STAT0.STAT1.STAT65 | BOOL | | FALSE | |
| 31.7 | Processor_Options.Blender_OPT._ProdPressReleaseRVM304 | BOOL | | FALSE | 0)Not Present 1)Present | | 31.7 | STAT0.STAT1.STAT66 | BOOL | | FALSE | |
| 32.0 | Processor_Options.Blender_OPT._VacuumPump | INT | 1 | 1 | 0)None 1)Sterling 2)Nash Elmo | | 32.0 | STAT0.STAT1.STAT67 | INT | 1 | 1 | |
| 34.0 | Processor_Options.Blender_OPT._GAS2InjectionType | INT | | 0 | 0)None 1)N2 2)Steril Air | | 34.0 | STAT0.STAT1.STAT68 | INT | | 0 | |
| 36.0 | Processor_Options.Blender_OPT._InjectionPress_Ctrl | INT | 1 | 1 | 0)Manual 1)Norgren v1 2)Norgren v2 | | 36.0 | STAT0.STAT1.STAT69 | INT | 1 | 1 | |
| 38.0 | Processor_Options.Blender_OPT._ProdPressureType | INT | | 0 | 0)Only CO2 1)CO2+SterilAir 2)CO2+N2 | | 38.0 | STAT0.STAT1.STAT70 | INT | | 0 | |
| 40.0 | Processor_Options.Blender_OPT._CIPHeatType | INT | | 0 | 0)Steam 1)Electric | | 40.0 | STAT0.STAT1.STAT71 | INT | | 0 | |
| 42.0 | Processor_Options.Blender_OPT._EHS_NrRes | INT | 6 | 6 | Number of Heat Resistances | | 42.0 | STAT0.STAT1.STAT72 | INT | 6 | 6 | |
| 44.0 | Spare1 | ARRAY [1..9] OF INT | | | | | 44.0 | STAT73 | ARRAY [1..9] OF INT | | | |
| 62.0 | _RVM301_DeadBand | REAL | 5.000000e-02 | 5.000000e-02 | | | 62.0 | STAT74 | REAL | 5.000000e-02 | 5.000000e-02 | |
| 66.0 | _RVM301_Kp | REAL | 9.000000e+01 | 9.000000e+01 | | | 66.0 | STAT75 | REAL | 6.500000e+01 | 9.000000e+01 | |
| 70.0 | Actual_Recipe_Parameters._Name | STRING[32] | ' ' | '' | | | 70.0 | STAT76.STAT77 | STRING[32] | ' ' | '' | |
| 104.0 | Actual_Recipe_Parameters._EnProdTemp | BOOL | | TRUE | | | 104.0 | STAT76.STAT78 | BOOL | | TRUE | |
| 104.1 | Actual_Recipe_Parameters._SyrFlushing | BOOL | | FALSE | Ex_EnDeaireation --> DELETED - AVP320 VALVE OPEN | | 104.1 | STAT76.STAT79 | BOOL | | FALSE | |
| 104.2 | Actual_Recipe_Parameters._GAS2_Injection | BOOL | | FALSE | 0 = GAS2 not present; 1 = GAS2 present | | 104.2 | STAT76.STAT80 | BOOL | | FALSE | |
| 104.3 | Actual_Recipe_Parameters._Eq_Pression_Selected | BOOL | | FALSE | | | 104.3 | STAT76.STAT81 | BOOL | | FALSE | |
| 104.4 | Actual_Recipe_Parameters._DeoxStripEn | BOOL | | FALSE | ******Deairation with Strip Enable | | 104.4 | STAT76.STAT82 | BOOL | | FALSE | |
| 104.5 | Actual_Recipe_Parameters._DeoxVacuumEn | BOOL | | TRUE | ******Deairation with Vacuum | | 104.5 | STAT76.STAT83 | BOOL | | TRUE | |
| 104.6 | Actual_Recipe_Parameters._DeoxPreMixed | BOOL | | FALSE | ******Deairation of Premixed Product | | 104.6 | STAT76.STAT84 | BOOL | | FALSE | |
| 104.7 | Actual_Recipe_Parameters._EnBlowOffProdPipeCO2Fil | BOOL | | FALSE | | | 104.7 | STAT76.STAT85 | BOOL | | FALSE | |
| 105.0 | Actual_Recipe_Parameters._WaterSelection | BYTE | | B#16#0 | | | 105.0 | STAT76.STAT86 | BYTE | | B#16#0 | |
| 106.0 | Actual_Recipe_Parameters._FillerNextRecipeNum | BYTE | | B#16#0 | | | 106.0 | STAT76.STAT87 | BYTE | | B#16#14 | |
| 107.0 | Actual_Recipe_Parameters._BottleShape | BYTE | | B#16#0 | | | 107.0 | STAT76.STAT88 | BYTE | | B#16#0 | |
| 108.0 | Actual_Recipe_Parameters._Type | INT | 1 | 2 | 1= DIET; 2= REGULAR; 3= RATIO; 4= WATER | | 108.0 | STAT76.STAT89 | INT | 1 | 2 | |
| 110.0 | Actual_Recipe_Parameters._ProdMeterRecipeNum | INT | | 1 | | | 110.0 | STAT76.STAT90 | INT | | 1 | |
| 112.0 | Actual_Recipe_Parameters._SyrupBrix | REAL | 5.000000e+01 | 4.625000e+01 | | | 112.0 | STAT76.STAT91 | REAL | 5.000000e+01 | 3.935000e+01 | |
| 116.0 | Actual_Recipe_Parameters._SyrupDensity | REAL | 1.255800e+00 | 1.206908e+00 | | | 116.0 | STAT76.STAT92 | REAL | 1.255800e+00 | 1.166600e+00 | |
| 120.0 | Actual_Recipe_Parameters._SyrupFactor | REAL | 1.000000e+00 | 1.000000e+00 | | | 120.0 | STAT76.STAT93 | REAL | 1.000000e+00 | 1.000000e+00 | |
| 124.0 | Actual_Recipe_Parameters._ProductBrix | REAL | 1.045000e+01 | 1.000000e+01 | | | 124.0 | STAT76.STAT94 | REAL | 1.045000e+01 | 8.600000e+00 | |
| 128.0 | Actual_Recipe_Parameters._ProductionRate | REAL | 9.000000e+02 | 3.800000e+02 | | | 128.0 | STAT76.STAT95 | REAL | 9.000000e+02 | 2.500000e-01 | |
| 132.0 | Actual_Recipe_Parameters._Ratio | REAL | 2.000000e+01 | 4.238896e+00 | | | 132.0 | STAT76.STAT96 | REAL | 2.000000e+01 | 3.934034e+00 | |
| 136.0 | Actual_Recipe_Parameters._ProdBrixOffset | REAL | | 2.500000e-01 | | | 136.0 | STAT76.STAT97 | REAL | | 4.000000e-01 | |
| 140.0 | Actual_Recipe_Parameters._CO2Vols | REAL | | 2.550000e+00 | | | 140.0 | STAT76.STAT98 | REAL | | 2.500000e+00 | |
| 144.0 | Actual_Recipe_Parameters._CO2Fact | REAL | 1.000000e+00 | 9.400000e-01 | | | 144.0 | STAT76.STAT99 | REAL | 1.000000e+00 | 9.000000e-01 | |
| 148.0 | Actual_Recipe_Parameters._ProdTankPress | REAL | 1.000000e+00 | 4.400000e+00 | | | 148.0 | STAT76.STAT100 | REAL | 1.000000e+00 | 3.500000e+00 | |
| 152.0 | Actual_Recipe_Parameters._SP_ProdTemp | REAL | 1.000000e+01 | 1.700000e+01 | | | 152.0 | STAT76.STAT101 | REAL | 1.000000e+01 | 1.600000e+01 | |
| 156.0 | Actual_Recipe_Parameters._PrdTankMinLevel | REAL | 1.000000e+01 | 3.500000e+01 | | | 156.0 | STAT76.STAT102 | REAL | 1.000000e+01 | 3.500000e+01 | |
| 160.0 | Actual_Recipe_Parameters._WaterValveSave | REAL | | 0.000000e+00 | | | 160.0 | STAT76.STAT103 | REAL | | 0.000000e+00 | |
| 164.0 | Actual_Recipe_Parameters._SyrupValveSave | REAL | | 0.000000e+00 | | | 164.0 | STAT76.STAT104 | REAL | | 0.000000e+00 | |
| 168.0 | Actual_Recipe_Parameters._CarboCO2ValveSave | REAL | | 0.000000e+00 | | | 168.0 | STAT76.STAT105 | REAL | | 0.000000e+00 | |
| 172.0 | Actual_Recipe_Parameters._ProdMeterHighBrix | REAL | | 1.030000e+01 | | | 172.0 | STAT76.STAT106 | REAL | | 8.800000e+00 | |
| 176.0 | Actual_Recipe_Parameters._ProdMeterLowBrix | REAL | | 9.830000e+00 | | | 176.0 | STAT76.STAT107 | REAL | | 8.400000e+00 | |
| 180.0 | Actual_Recipe_Parameters._ProdMeterHighCO2 | REAL | | 2.900000e+00 | | | 180.0 | STAT76.STAT108 | REAL | | 2.800000e+00 | |
| 184.0 | Actual_Recipe_Parameters._ProdMeterLowCO2 | REAL | | 2.300000e+00 | | | 184.0 | STAT76.STAT109 | REAL | | 2.200000e+00 | |
| 188.0 | Actual_Recipe_Parameters._ProdMeter_ZeroCO2 | REAL | | 0.000000e+00 | | | 188.0 | STAT76.STAT110 | REAL | | 0.000000e+00 | |
| 192.0 | Actual_Recipe_Parameters._ProdMeter_ZeroBrix | REAL | | 0.000000e+00 | | | 192.0 | STAT76.STAT111 | REAL | | 0.000000e+00 | |
| 196.0 | Actual_Recipe_Parameters._ProdHighCond | REAL | | 0.000000e+00 | | | 196.0 | STAT76.STAT112 | REAL | | 0.000000e+00 | |
| 200.0 | Actual_Recipe_Parameters._ProdLowCond | REAL | | 0.000000e+00 | | | 200.0 | STAT76.STAT113 | REAL | | 0.000000e+00 | |
| 204.0 | Actual_Recipe_Parameters._BottleSize | REAL | | 0.000000e+00 | | | 204.0 | STAT76.STAT114 | REAL | | 0.000000e+00 | |
| 208.0 | Actual_Recipe_Parameters._FillingValveHead_SP | REAL | | 0.000000e+00 | | | 208.0 | STAT76.STAT115 | REAL | | 0.000000e+00 | |
| 212.0 | Actual_Recipe_Parameters._SyrMeter_ZeroBrix | REAL | | 0.000000e+00 | | | 212.0 | STAT76.STAT116 | REAL | | 0.000000e+00 | |
| 216.0 | Actual_Recipe_Parameters._FirstProdExtraCO2Fact | REAL | 9.700000e-01 | 1.020000e+00 | | | 216.0 | STAT76.STAT117 | REAL | 9.700000e-01 | 8.500000e-01 | |
| 220.0 | Actual_Recipe_Parameters._Gas2Vols | REAL | | 0.000000e+00 | | | 220.0 | STAT76.STAT118 | REAL | | 0.000000e+00 | |
| 224.0 | Actual_Recipe_Parameters._Gas2Fact | REAL | 1.000000e+00 | 0.000000e+00 | | | 224.0 | STAT76.STAT119 | REAL | 1.000000e+00 | 0.000000e+00 | |
| 228.0 | Actual_Recipe_Parameters._SyrupPumpPressure | REAL | | 0.000000e+00 | ******Syrup Pump Pressure SP | | 228.0 | STAT76.STAT120 | REAL | | 0.000000e+00 | |
| 232.0 | Actual_Recipe_Parameters._WaterPumpPressure | REAL | | 0.000000e+00 | ******Water Pump Pressure SP | | 232.0 | STAT76.STAT121 | REAL | | 0.000000e+00 | |
| 236.0 | Actual_Recipe_Parameters._CO2_Air_N2_PressSelect | INT | | 0 | 1=CO2; 2=CO2+SterilAir; 3=CO2+N2 - Pressure Tank Selection | | 236.0 | STAT76.STAT122 | INT | | 0 | |
| 238.0 | Actual_Recipe_Parameters._KFactRVM304BlowOff | REAL | | 0.000000e+00 | | | 238.0 | STAT76.STAT123 | REAL | | 0.000000e+00 | |
| 242.0 | Actual_Recipe_Parameters._ProdRecircPumpFreq | REAL | | 0.000000e+00 | | | 242.0 | STAT76.STAT124 | REAL | | 0.000000e+00 | |
| 246.0 | Actual_Recipe_Parameters._ProdBoosterPumpPress | REAL | | 0.000000e+00 | | | 246.0 | STAT76.STAT125 | REAL | | 0.000000e+00 | |
| 250.0 | Actual_Recipe_Parameters._ProdSendPumpFreq | REAL | | 0.000000e+00 | ******Product Sending Pump Frequency SP | | 250.0 | STAT76.STAT126 | REAL | | 0.000000e+00 | |
| 254.0 | Spare2 | ARRAY [1..5] OF INT | | | | | 254.0 | STAT127 | ARRAY [1..5] OF INT | | | |
| 264.0 | Next_Recipe_Name | STRING[32] | ' ' | 'cambio 1$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00' | | | 264.0 | STAT128 | STRING[32] | ' ' | '' | |
| 298.0 | Next_Recipe_Number | INT | | 0 | | | 298.0 | STAT129 | INT | | 0 | |
| 300.0 | Spare3 | ARRAY [1..18] OF INT | | | | | 300.0 | STAT130 | ARRAY [1..18] OF INT | | | |
| 336.0 | ProcessSetup.Spare000 | REAL | | 0.000000e+00 | | | 336.0 | STAT131.STAT132 | REAL | | 0.000000e+00 | |
| 340.0 | ProcessSetup.Spare040 | REAL | | 0.000000e+00 | | | 340.0 | STAT131.STAT133 | REAL | | 0.000000e+00 | |
| 344.0 | ProcessSetup._KWaterLoss | REAL | 1.000000e-03 | 1.000000e-03 | Friction Loss Constant in Serpentine | | 344.0 | STAT131.STAT134 | REAL | 1.580000e-03 | 1.000000e-03 | |
| 348.0 | ProcessSetup._KSyrupLoss | REAL | 7.800000e-03 | 7.800000e-03 | Friction Loss Constant in Syrup Pipe | | 348.0 | STAT131.STAT135 | REAL | 9.000000e-03 | 7.800000e-03 | |
| 352.0 | ProcessSetup._KProdLoss | REAL | 1.390000e-02 | 1.390000e-02 | Pressure Loss Factor | | 352.0 | STAT131.STAT136 | REAL | 1.700000e-02 | 1.390000e-02 | |
| 356.0 | ProcessSetup._KPPM303 | REAL | 5.700000e+00 | 5.700000e+00 | Frequency Overpressure Pump P3 Constant [Hz/mm] | | 356.0 | STAT131.STAT137 | REAL | 5.700000e+00 | 5.700000e+00 | |
| 360.0 | ProcessSetup._BaialageRVM301OVMin | REAL | 2.000000e+00 | 2.000000e+00 | Baialage Minimum Flow (Nm3/h) | | 360.0 | STAT131.STAT138 | REAL | 2.000000e+00 | 2.000000e+00 | |
| 364.0 | ProcessSetup._SyrupLinePressure | REAL | 2.200000e+00 | 2.200000e+00 | Syrup Line pressure at VEP2 valve | | 364.0 | STAT131.STAT139 | REAL | 2.000000e+00 | 2.200000e+00 | |
| 368.0 | ProcessSetup._CIPRMM301OV | REAL | 1.000000e+01 | 1.000000e+01 | Water Valve Opening During CIP | | 368.0 | STAT131.STAT140 | REAL | 1.000000e+01 | 2.100000e+01 | |
| 372.0 | ProcessSetup._CIPRMP302OV | REAL | 1.500000e+01 | 1.500000e+01 | Syrup Valve Opening During CIP | | 372.0 | STAT131.STAT141 | REAL | 1.000000e+01 | 2.000000e+01 | |
| 376.0 | ProcessSetup._CIPTM301MinLevel | REAL | 3.500000e+01 | 3.500000e+01 | Product Tank Minimum Level In CIP | | 376.0 | STAT131.STAT142 | REAL | 1.000000e+01 | 5.000000e+00 | |
| 380.0 | ProcessSetup._CIPTM301MaxLevel | REAL | 5.500000e+01 | 5.500000e+01 | Product Tank Maximum Level In CIP | | 380.0 | STAT131.STAT143 | REAL | 6.000000e+01 | 6.000000e+01 | |
| 384.0 | ProcessSetup._CIPPPM303Freq | REAL | 5.000000e+01 | 5.000000e+01 | CIP frequency Value [Hz] | | 384.0 | STAT131.STAT144 | REAL | 5.000000e+01 | 5.000000e+01 | |
| 388.0 | ProcessSetup._CIPTP301MinLevel | REAL | 2.500000e+01 | 2.500000e+01 | Syrup Tank Minimum Level In CIP | | 388.0 | STAT131.STAT145 | REAL | 2.500000e+01 | 2.500000e+01 | |
| 392.0 | ProcessSetup._CIPTP301MaxLevel | REAL | 4.500000e+01 | 4.500000e+01 | Syrup Tank Maximum Level In CIP | | 392.0 | STAT131.STAT146 | REAL | 6.500000e+01 | 4.000000e+01 | |
| 396.0 | ProcessSetup._RinseRMM301OV | REAL | 1.000000e+01 | 1.000000e+01 | Water Valve Opening During Rinse | | 396.0 | STAT131.STAT147 | REAL | 1.200000e+01 | 2.400000e+01 | |
| 400.0 | ProcessSetup._RinseRMP302OV | REAL | 1.400000e+01 | 1.400000e+01 | Syrup Valve Opening During Rinse | | 400.0 | STAT131.STAT148 | REAL | 1.000000e+01 | 1.400000e+01 | |
| 404.0 | ProcessSetup._RinseTM301Press | REAL | 3.000000e-01 | 3.000000e-01 | Product Tank Pressure In Rinse | | 404.0 | STAT131.STAT149 | REAL | | 3.000000e-01 | |
| 408.0 | ProcessSetup._RinsePPM303Freq | REAL | 5.000000e+01 | 5.000000e+01 | Rinse frequency Value [Hz] | | 408.0 | STAT131.STAT150 | REAL | 3.000000e+01 | 3.000000e+01 | |
| 412.0 | ProcessSetup._DrainTM301Press | REAL | 1.000000e+00 | 1.000000e+00 | Buffer Tank Draining Pressure | | 412.0 | STAT131.STAT151 | REAL | 1.000000e+00 | 1.000000e+00 | |
| 416.0 | ProcessSetup._KRecBlendError | REAL | 2.000000e+00 | 2.000000e+00 | Blend Error Recovery CONSTANT | | 416.0 | STAT131.STAT152 | REAL | 5.000000e+00 | 4.000000e+00 | |
| 420.0 | ProcessSetup._KRecCarboCO2Error | REAL | 2.000000e+00 | 2.000000e+00 | Carbonation Error Recovery Constant | | 420.0 | STAT131.STAT153 | REAL | 5.000000e+00 | 2.000000e+00 | |
| 424.0 | ProcessSetup._MaxBlendError | REAL | 1.000000e+02 | 1.000000e+02 | Blend Error Maximum Value | | 424.0 | STAT131.STAT154 | REAL | 1.000000e+02 | 1.000000e+02 | |
| 428.0 | ProcessSetup._MaxCarboCO2Error | REAL | 5.000000e+02 | 5.000000e+02 | Carbonation Error Maximum Value | | 428.0 | STAT131.STAT155 | REAL | 2.000000e+02 | 5.000000e+02 | |
| 432.0 | ProcessSetup._StartUpBrixExtraWater | REAL | 4.700000e+01 | 4.700000e+01 | | | 432.0 | STAT131.STAT156 | REAL | 2.000000e+01 | 5.000000e+01 | |
| 436.0 | ProcessSetup._StartUpCO2ExtraWater | REAL | 8.000000e+00 | 8.000000e+00 | | | 436.0 | STAT131.STAT157 | REAL | 2.000000e+01 | 8.000000e+00 | |
| 440.0 | ProcessSetup._StartUpPPM303Freq | REAL | 2.000000e+01 | 2.000000e+01 | Start Up frequency Value [Hz] | | 440.0 | STAT131.STAT158 | REAL | 2.000000e+01 | 1.900000e+01 | |
| 444.0 | ProcessSetup._SyrupRoomTank | INT | 1 | 1 | | | 444.0 | STAT131.STAT159 | INT | 1 | 1 | |
| 446.0 | ProcessSetup._SyrupRunOutLiters | REAL | 2.900000e+02 | 2.900000e+02 | | | 446.0 | STAT131.STAT160 | REAL | 2.000000e+01 | 2.000000e+02 | |
| 450.0 | ProcessSetup._InjCO2Press_Offset | REAL | 5.000000e-01 | 5.000000e-01 | | | 450.0 | STAT131.STAT161 | REAL | 7.000000e-01 | 5.000000e-01 | |
| 454.0 | ProcessSetup._InjCO2Press_MinFlow | REAL | 4.500000e+02 | 4.500000e+02 | | | 454.0 | STAT131.STAT162 | REAL | 4.250000e+02 | 4.500000e+02 | |
| 458.0 | ProcessSetup._InjCO2Press_MaxFlow | REAL | 2.500000e+03 | 2.500000e+03 | | | 458.0 | STAT131.STAT163 | REAL | 2.550000e+03 | 2.500000e+03 | |
| 462.0 | ProcessSetup._CarboCO2Pressure | REAL | 1.250000e+01 | 1.250000e+01 | CO2 Pressure Infeed Line | | 462.0 | STAT131.STAT164 | REAL | 9.000000e+00 | 1.220000e+01 | |
| 466.0 | ProcessSetup._N2MinPressure | REAL | 1.000000e+00 | 1.000000e+00 | N2 Minimum Pressure Infeed Line | | 466.0 | STAT131.STAT165 | REAL | | 1.000000e+00 | |
| 470.0 | ProcessSetup._DiffSensor_Height | REAL | 3.950000e+02 | 3.950000e+02 | Sensor Height from Soil [mm] | | 470.0 | STAT131.STAT166 | REAL | 1.600000e+03 | 3.950000e+02 | |
| 474.0 | ProcessSetup._DiffSensor_DeltaHeight | REAL | -2.500000e+01 | -2.500000e+01 | Sensor Plates Height Difference [mm] | | 474.0 | STAT131.STAT167 | REAL | 2.000000e+01 | -2.500000e+01 | |
| 478.0 | ProcessSetup._DiffSensor_Offset | REAL | 3.618000e+01 | 3.618000e+01 | Sensor Offset Read with zero pressure (all valves open) in [mm] | | 478.0 | STAT131.STAT168 | REAL | 1.400000e+01 | 3.618000e+01 | |
| 482.0 | ProcessSetup._FillingValveHeight | REAL | 1.400000e+03 | 1.400000e+03 | Filling Valve Height from soil [mm] | | 482.0 | STAT131.STAT169 | REAL | 1.610000e+03 | 1.400000e+03 | |
| 486.0 | ProcessSetup._FillerDiameter | REAL | 2.520000e+03 | 2.520000e+03 | Filler Carousel Diameter [mm] | | 486.0 | STAT131.STAT170 | REAL | 2.877000e+03 | 2.520000e+03 | |
| 490.0 | ProcessSetup._FillingValveNum | INT | 91 | 91 | Filling Valves Number | | 490.0 | STAT131.STAT171 | INT | 80 | 91 | |
| 492.0 | ProcessSetup._FillerProdPipeDN | REAL | 1.000000e+02 | 1.000000e+02 | | | 492.0 | STAT131.STAT172 | REAL | 8.000000e+01 | 1.000000e+02 | |
| 496.0 | ProcessSetup._FillerProdPipeMass | REAL | 1.600000e+02 | 1.600000e+02 | | | 496.0 | STAT131.STAT173 | REAL | 9.000000e+01 | 1.600000e+02 | |
| 500.0 | ProcessSetup._FillingTime | REAL | 3.200000e+00 | 3.200000e+00 | | | 500.0 | STAT131.STAT174 | REAL | 4.000000e+00 | 3.200000e+00 | |
| 504.0 | ProcessSetup._TM301Height_0 | REAL | 1.050000e+03 | 1.050000e+03 | Level at 0% Tank Level Height in mm | | 504.0 | STAT131.STAT175 | REAL | 1.020000e+03 | 1.050000e+03 | |
| 508.0 | ProcessSetup._TM301LevelPerc_2 | REAL | 4.600000e+01 | 4.600000e+01 | Second level percentage | | 508.0 | STAT131.STAT176 | REAL | 1.000000e+02 | 4.600000e+01 | |
| 512.0 | ProcessSetup._TM301Height_2 | REAL | 1.625000e+03 | 1.625000e+03 | Second level Height in mm | | 512.0 | STAT131.STAT177 | REAL | 2.300000e+03 | 1.625000e+03 | |
| 516.0 | ProcessSetup._RVN304Factor | REAL | 1.000000e+00 | 1.000000e+00 | DeareationFlow/WaterFlow | | 516.0 | STAT131.STAT178 | REAL | 7.500000e-01 | 1.000000e+00 | |
| 520.0 | ProcessSetup._DrainTM301Flushing | REAL | 1.300000e+00 | 1.300000e+00 | | | 520.0 | STAT131.STAT179 | REAL | 5.000000e-01 | 1.300000e+00 | |
| 524.0 | ProcessSetup._FirstProdExtraBrix | REAL | 5.000000e-02 | 5.000000e-02 | | | 524.0 | STAT131.STAT180 | REAL | 3.000000e-02 | 4.090000e-02 | |
| 528.0 | ProcessSetup._FirstProdDietExtraSyr | REAL | 1.400000e-03 | 1.400000e-03 | | | 528.0 | STAT131.STAT181 | REAL | 1.400000e-03 | 1.400000e-03 | |
| 532.0 | ProcessSetup._EndProdLastSyrlt | REAL | | 0.000000e+00 | End Production Last syrup liters | | 532.0 | STAT131.STAT182 | REAL | | 4.500000e+02 | |
| 536.0 | ProcessSetup._TM301DrainSt0Time | WORD | W#16#A | W#16#A | sec | | 536.0 | STAT131.STAT183 | WORD | W#16#6 | W#16#0 | |
| 538.0 | ProcessSetup._TM301DrainSt1Time | WORD | W#16#50 | W#16#50 | sec | | 538.0 | STAT131.STAT184 | WORD | W#16#50 | W#16#78 | |
| 540.0 | ProcessSetup._ProdPipeRunOutSt0Time | WORD | W#16#1 | W#16#1 | sec | | 540.0 | STAT131.STAT185 | WORD | W#16#1 | W#16#1 | |
| 542.0 | ProcessSetup._RMM301ProdPipeRunOu | REAL | 3.000000e+01 | 3.000000e+01 | | | 542.0 | STAT131.STAT186 | REAL | 3.000000e+01 | 3.000000e+01 | |
| 546.0 | ProcessSetup._RMP302ProdPipeRunOu | REAL | 4.000000e+01 | 4.000000e+01 | | | 546.0 | STAT131.STAT187 | REAL | 4.000000e+01 | 4.000000e+01 | |
| 550.0 | ProcessSetup._ProdPipeRunOutAmount | REAL | 3.000000e+01 | 3.000000e+01 | | | 550.0 | STAT131.STAT188 | REAL | 9.000000e+01 | 3.000000e+01 | |
| 554.0 | ProcessSetup._TM301RunOutChiller | REAL | 5.000000e+00 | 5.000000e+00 | | | 554.0 | STAT131.STAT189 | REAL | 2.500000e+02 | 5.000000e+00 | |
| 558.0 | ProcessSetup._MinSpeedNominalProd | REAL | 4.000000e-01 | 4.000000e-01 | Min Speed for Nominal Production | | 558.0 | STAT131.STAT190 | REAL | 5.500000e-01 | 4.900000e-01 | |
| 562.0 | ProcessSetup._MinSpeedSlowProd | REAL | 3.000000e-01 | 3.000000e-01 | Min Speed for Very Low Production | | 562.0 | STAT131.STAT191 | REAL | 4.000000e-01 | 3.000000e-01 | |
| 566.0 | ProcessSetup._FastChgOvrTM301DrnPrss | REAL | 9.000000e-01 | 9.000000e-01 | Fast Change Over Product Tank Draining Pressure in Blendfill | | 566.0 | STAT131.STAT192 | REAL | 9.000000e-01 | 9.000000e-01 | |
| 570.0 | ProcessSetup._CIPTN301MinLevel | REAL | 3.500000e+01 | 3.500000e+01 | Deaireator Tank Minimum Level In CIP | | 570.0 | STAT131.STAT193 | REAL | 1.500000e+01 | 1.500000e+01 | |
| 574.0 | ProcessSetup._CIPTN301MaxLevel | REAL | 6.000000e+01 | 6.000000e+01 | Deaireator Tank Maximum Level In CIP | | 574.0 | STAT131.STAT194 | REAL | 4.500000e+01 | 3.500000e+01 | |
| 578.0 | ProcessSetup._ProdPPN304Freq | REAL | 5.000000e+01 | 5.000000e+01 | | | 578.0 | STAT131.STAT195 | REAL | 5.000000e+01 | 5.000000e+01 | |
| 582.0 | ProcessSetup._GAS2InjectionPress | REAL | 4.000000e+00 | 4.000000e+00 | | | 582.0 | STAT131.STAT196 | REAL | 4.000000e+00 | 4.000000e+00 | |
| 586.0 | ProcessSetup._BaialageRVM301OVMax | REAL | 2.000000e+01 | 2.000000e+01 | Baialage Production Flow Multiplier | | 586.0 | STAT131.STAT197 | REAL | 2.000000e+01 | 2.000000e+01 | |
| 590.0 | ProcessSetup._RinsePPN301Freq | REAL | 5.000000e+00 | 5.000000e+00 | | | 590.0 | STAT131.STAT198 | REAL | 5.000000e+00 | 5.000000e+00 | |
| 594.0 | ProcessSetup._CIPPPN301Freq | REAL | 5.000000e+00 | 5.000000e+00 | | | 594.0 | STAT131.STAT199 | REAL | 5.000000e+00 | 5.000000e+00 | |
| 598.0 | ProcessSetup._RinsePPP302Freq | REAL | 5.000000e+00 | 5.000000e+00 | | | 598.0 | STAT131.STAT200 | REAL | 5.000000e+00 | 5.000000e+00 | |
| 602.0 | ProcessSetup._CIPPPP302Freq | REAL | 5.000000e+00 | 5.000000e+00 | | | 602.0 | STAT131.STAT201 | REAL | 5.000000e+00 | 5.000000e+00 | |
| 606.0 | ProcessSetup._PercSyrupBrixSyrStarUp | REAL | 2.500000e+01 | 2.500000e+01 | | | 606.0 | STAT131.STAT202 | REAL | 1.000000e+01 | 6.000000e+01 | |
| 610.0 | ProcessSetup._RefTempCoolingCTRL | REAL | | 0.000000e+00 | | | 610.0 | STAT131.STAT203 | REAL | | 0.000000e+00 | |
| 614.0 | ProcessSetup._H2OSerpPrimingVolume | REAL | 1.500000e+02 | 1.500000e+02 | Water Serpentine Volume + Water Chiller Volume | | 614.0 | STAT131.STAT204 | REAL | 1.150000e+02 | 1.500000e+02 | |
| 618.0 | ProcessSetup._AVN301_Nozzle_Kv | REAL | 1.650000e+02 | 1.650000e+02 | AVN301 Nozzle Kv | | 618.0 | STAT131.STAT205 | REAL | 1.650000e+02 | 1.650000e+02 | |
| 622.0 | ProcessSetup._AVN302_Nozzle_Kv | REAL | 2.600000e+02 | 2.600000e+02 | AVN302 Nozzle Kv | | 622.0 | STAT131.STAT206 | REAL | 2.600000e+02 | 2.600000e+02 | |
| 626.0 | ProcessSetup._AVN303_Nozzle_Kv | REAL | 1.650000e+02 | 1.650000e+02 | AVN303 Nozzle Kv | | 626.0 | STAT131.STAT207 | REAL | 1.650000e+02 | 1.650000e+02 | |
| 630.0 | ProcessSetup._DeoxSpryball_Kv | REAL | 6.700000e+01 | 6.700000e+01 | Deox Spryball Kv | | 630.0 | STAT131.STAT208 | REAL | 6.700000e+01 | 6.700000e+01 | |
| 634.0 | ProcessSetup._PremixedLineDrainTime | INT | 300 | 300 | Premixed Product Line Drain Time | | 634.0 | STAT131.STAT209 | INT | 50 | 300 | |
| 636.0 | ProcessSetup._PPN301_H_MaxFlow | REAL | 9.000000e+01 | 9.000000e+01 | PPN301 Pump Head with Max Flow [m] | | 636.0 | STAT131.STAT210 | REAL | 9.000000e+01 | 9.000000e+01 | |
| 640.0 | ProcessSetup._PPN301_H_MinFlow | REAL | 8.700000e+01 | 8.700000e+01 | PPN301 Pump Head with Min Flow [m] | | 640.0 | STAT131.STAT211 | REAL | 8.700000e+01 | 8.700000e+01 | |
| 644.0 | ProcessSetup._PPN301_MaxFlow | REAL | 5.070000e+02 | 5.070000e+02 | PPN301 Max Flow [l/min] | | 644.0 | STAT131.STAT212 | REAL | 5.070000e+02 | 5.070000e+02 | |
| 648.0 | ProcessSetup._PPN301_MinFlow | REAL | 2.110000e+02 | 2.110000e+02 | PPN301 Min Flow [l/min] | | 648.0 | STAT131.STAT213 | REAL | 2.110000e+02 | 2.110000e+02 | |
| 652.0 | ProcessSetup._PPP302_H_MaxFlow | REAL | 8.600000e+01 | 8.600000e+01 | PPP302 Pump Head with Max Flow [m] | | 652.0 | STAT131.STAT214 | REAL | 8.600000e+01 | 8.600000e+01 | |
| 656.0 | ProcessSetup._PPP302_H_MinFlow | REAL | 8.500000e+01 | 8.500000e+01 | PPP302 Pump Head with Min Flow [m] | | 656.0 | STAT131.STAT215 | REAL | 8.500000e+01 | 8.500000e+01 | |
| 660.0 | ProcessSetup._PPP302_MaxFlow | REAL | 1.150000e+02 | 1.150000e+02 | PPP302 Max Flow [l/min] | | 660.0 | STAT131.STAT216 | REAL | 1.150000e+02 | 1.150000e+02 | |
| 664.0 | ProcessSetup._PPP302_MinFlow | REAL | 3.200000e+01 | 3.200000e+01 | PPP302 Min Flow [l/min] | | 664.0 | STAT131.STAT217 | REAL | 3.200000e+01 | 3.200000e+01 | |
| 668.0 | ProcessSetup._RinsePPM306Freq | REAL | 5.000000e+00 | 5.000000e+00 | | | 668.0 | STAT131.STAT218 | REAL | 5.000000e+00 | 5.000000e+00 | |
| 672.0 | ProcessSetup._CIPPPM306Freq | REAL | 5.000000e+00 | 5.000000e+00 | | | 672.0 | STAT131.STAT219 | REAL | 5.000000e+00 | 5.000000e+00 | |
| 676.0 | ProcessSetup._PPM307_H_MaxFlow | REAL | | 0.000000e+00 | PPM307 Pump Head with Max Flow [m] | | 676.0 | STAT131.STAT220 | REAL | | 0.000000e+00 | |
| 680.0 | ProcessSetup._PPM307_H_MinFlow | REAL | | 0.000000e+00 | PPM307 Pump Head with Min Flow [m] | | 680.0 | STAT131.STAT221 | REAL | | 0.000000e+00 | |
| 684.0 | ProcessSetup._PPM307_MaxFlow | REAL | | 0.000000e+00 | PPM307 Max Flow [l/min] | | 684.0 | STAT131.STAT222 | REAL | | 0.000000e+00 | |
| 688.0 | ProcessSetup._PPM307_MinFlow | REAL | | 0.000000e+00 | PPM307 Min Flow [l/min] | | 688.0 | STAT131.STAT223 | REAL | | 0.000000e+00 | |
| 692.0 | ProcessSetup._Temp0_VacuumCtrl | REAL | 1.800000e+01 | 1.800000e+01 | PPN304 Target Temperature - OPTION PPN304 Sterling Type | | 692.0 | STAT131.STAT224 | REAL | 1.800000e+01 | 2.000000e+01 | |
| 696.0 | ProcessSetup._Temp1_VacuumCtrl | REAL | 2.000000e+00 | 2.000000e+00 | PPN304 High Treshold Temperature Delta - OPTION PPN304 Sterling Type | | 696.0 | STAT131.STAT225 | REAL | 2.000000e+00 | 5.000000e+00 | |
| 700.0 | ProcessSetup._Temp2_VacuumCtrl | REAL | 2.000000e+00 | 2.000000e+00 | PPN304 Low Treshold Temperature Delta - OPTION PPN304 Sterling Type | | 700.0 | STAT131.STAT226 | REAL | 2.000000e+00 | 1.000000e+01 | |
| 704.0 | ProcessSetup._Temp3_VacuumCtrl | REAL | 5.000000e+01 | 5.000000e+01 | PPN304 Warning Temperature - OPTION PPN304 Sterling Type | | 704.0 | STAT131.STAT227 | REAL | 5.000000e+01 | 5.000000e+01 | |
| 708.0 | ProcessSetup._Temp4_VacuumCtrl | REAL | 5.000000e+01 | 5.000000e+01 | PPN304 Alarm Temperature - OPTION PPN304 Sterling Type | | 708.0 | STAT131.STAT228 | REAL | 5.000000e+01 | 5.000000e+01 | |
| 712.0 | ProcessSetup._T1_VacuumCtrl | DINT | L#1500 | L#1500 | PPN304 Time 1 [msec] - OPTION PPN304 Sterling Type | | 712.0 | STAT131.STAT229 | DINT | L#1500 | L#1500 | |
| 716.0 | ProcessSetup._T2_VacuumCtrl | DINT | L#1500 | L#1500 | PPN304 Time 2 [msec] - OPTION PPN304 Sterling Type | | 716.0 | STAT131.STAT230 | DINT | L#1500 | L#1500 | |
| 720.0 | ProcessSetup._T3_VacuumCtrl | DINT | L#1000 | L#1000 | PPN304 Time 3 [msec] - OPTION PPN304 Sterling Type | | 720.0 | STAT131.STAT231 | DINT | L#1000 | L#1000 | |
| 724.0 | ProcessSetup._T4_VacuumCtrl | DINT | L#1000 | L#1000 | PPN304 Time 4 [msec] - OPTION PPN304 Sterling Type | | 724.0 | STAT131.STAT232 | DINT | L#1000 | L#1000 | |
| 728.0 | ProcessSetup._ICS_VolDosWorkTimePAA | INT | 30 | 30 | ICS - DS - Dosing Working Time [sec] | | 728.0 | STAT131.STAT233 | INT | 30 | 30 | |
| 730.0 | ProcessSetup._ICS_VolPauseTimePAA | INT | 30 | 30 | ICS - DS - Dosing Pause Time [sec] | | 730.0 | STAT131.STAT234 | INT | 30 | 30 | |
| 732.0 | ProcessSetup._ICS_PAAPulseWeight | INT | 10 | 10 | ICS - DS - PAA Pulse Weight [(L/Pulse)/100] | | 732.0 | STAT131.STAT235 | INT | 10 | 10 | |
| 734.0 | ProcessSetup._ICS_CausticPulseWeight | INT | 10 | 10 | ICS - DS - Caustic Pulse Weight [(L/Pulse)/100] | | 734.0 | STAT131.STAT236 | INT | 10 | 10 | |
| 736.0 | ProcessSetup._ICS_AcidPulseWeight | INT | 10 | 10 | ICS - DS - Acid Pulse Weight [(L/Pulse)/100] | | 736.0 | STAT131.STAT237 | INT | 10 | 10 | |
| 738.0 | ProcessSetup._ICS_VolumeRestOfLine | REAL | 3.500000e+02 | 3.500000e+02 | ICS - DS - Volume of the Rest of the Line (Filler + Piping) [L] | | 738.0 | STAT131.STAT238 | REAL | 3.500000e+02 | 3.500000e+02 | |
| 742.0 | ProcessSetup._ICS_VolDosWorkTimeCaus | INT | 30 | 30 | ICS - DS - Dosing Working Time [sec] | | 742.0 | STAT131.STAT239 | INT | 30 | 30 | |
| 744.0 | ProcessSetup._ICS_VolDosPauseTimeCaus | INT | 30 | 30 | ICS - DS - Dosing Pause Time [sec] | | 744.0 | STAT131.STAT240 | INT | 30 | 30 | |
| 746.0 | ProcessSetup._ICS_VolDosWorkTimeAcid | INT | 30 | 30 | ICS - DS - Dosing Working Time [sec] | | 746.0 | STAT131.STAT241 | INT | 30 | 30 | |
| 748.0 | ProcessSetup._ICS_VolDosPauseTimeAcid | INT | 30 | 30 | ICS - DS - Dosing Pause Time [sec] | | 748.0 | STAT131.STAT242 | INT | 30 | 30 | |
| 750.0 | ProcessSetup._ICS_ConcDosWorkTimeCaus | INT | 30 | 30 | ICS - DS - Dosing Working Time [sec] | | 750.0 | STAT131.STAT243 | INT | 30 | 30 | |
| 752.0 | ProcessSetup._ICS_ConcDosPausTimeCaus | INT | 30 | 30 | ICS - DS - Dosing Pause Time [sec] | | 752.0 | STAT131.STAT244 | INT | 30 | 30 | |
| 754.0 | ProcessSetup._ICS_ConcDosWorkTimeAcid | INT | 30 | 30 | ICS - DS - Dosing Working Time [sec] | | 754.0 | STAT131.STAT245 | INT | 30 | 30 | |
| 756.0 | ProcessSetup._ICS_ConcDosPausTimeAcid | INT | 30 | 30 | ICS - DS - Dosing Pause Time [sec] | | 756.0 | STAT131.STAT246 | INT | 30 | 30 | |
| 758.0 | ProcessSetup._RinsePPM307Freq | REAL | 3.000000e+01 | 3.000000e+01 | | | 758.0 | STAT131.STAT247 | REAL | 3.000000e+01 | 3.000000e+01 | |
| 762.0 | ProcessSetup._CIPPPM307Freq | REAL | 3.000000e+01 | 3.000000e+01 | | | 762.0 | STAT131.STAT248 | REAL | 3.000000e+01 | 3.000000e+01 | |
| 766.0 | ProcessSetup._CIP2StepTN301Lvl | REAL | | 0.000000e+00 | Local CIP - 2 Step loading TN301 Level | | 766.0 | STAT131.STAT249 | REAL | | 0.000000e+00 | |
| 770.0 | ProcessSetup._CIP2StepTM301Lvl | REAL | | 0.000000e+00 | Local CIP - 2 Step loading TM301 Level | | 770.0 | STAT131.STAT250 | REAL | | 0.000000e+00 | |
| 774.0 | ProcessSetup._CIP2StepTP301Lvl | REAL | | 0.000000e+00 | Local CIP - 2 Step loading TP301 Level | | 774.0 | STAT131.STAT251 | REAL | | 0.000000e+00 | |
| 778.0 | ProcessSetup._PumpNominalFreq | REAL | 5.000000e+01 | 5.000000e+01 | 50.0 Hz or 60.0 Hz | | 778.0 | STAT131.STAT252 | REAL | 5.000000e+01 | 5.000000e+01 | |
| 782.0 | _SwitchOff_DensityOK | BOOL | | FALSE | | | 782.0 | STAT253 | BOOL | | FALSE | |
| 784.0 | STAT254 | REAL | | 0.000000e+00 | |

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
TYPE "Recipe_Prod" TYPE "Recipe_Prod"
FAMILY : DataType; FAMILY : DataType
VERSION : 0.1; VERSION : 0.1
STRUCT STRUCT
_Name : STRING[32] := ' '; _Name : STRING[32] := ' ';
@ -54,11 +54,12 @@ TYPE "Recipe_Prod"
_ProdBoosterPumpPress : REAL; _ProdBoosterPumpPress : REAL;
_ProdSendPumpFreq : REAL; // ******Product Sending Pump Frequency SP _ProdSendPumpFreq : REAL; // ******Product Sending Pump Frequency SP
END_STRUCT; END_STRUCT;
END_TYPE; END_TYPE
DATA_BLOCK "HMI_Blender_Parameters" DATA_BLOCK "HMI_Blender_Parameters"
FAMILY : Resource; TITLE = { S7_language := '28(1) Albanese 15.06.2005 17:07:04' }
VERSION : 0.0; FAMILY : Resource
VERSION : 0.0
STRUCT STRUCT
Processor_Options : STRUCT Processor_Options : STRUCT
@ -270,250 +271,77 @@ DATA_BLOCK "HMI_Blender_Parameters"
_SwitchOff_DensityOK : BOOL; _SwitchOff_DensityOK : BOOL;
END_STRUCT; END_STRUCT;
BEGIN BEGIN
Actual_Recipe_Parameters._BottleShape := B#16#0;
Actual_Recipe_Parameters._BottleSize := 0.000000e+00;
Actual_Recipe_Parameters._CO2Fact := 9.400000e-01;
Actual_Recipe_Parameters._CO2Vols := 2.550000e+00;
Actual_Recipe_Parameters._CO2_Air_N2_PressSelect := 0;
Actual_Recipe_Parameters._CarboCO2ValveSave := 0.000000e+00;
Actual_Recipe_Parameters._DeoxPreMixed := FALSE;
Actual_Recipe_Parameters._DeoxStripEn := FALSE;
Actual_Recipe_Parameters._DeoxVacuumEn := TRUE;
Actual_Recipe_Parameters._EnBlowOffProdPipeCO2Fil := FALSE;
Actual_Recipe_Parameters._EnProdTemp := TRUE;
Actual_Recipe_Parameters._Eq_Pression_Selected := FALSE;
Actual_Recipe_Parameters._FillerNextRecipeNum := B#16#0;
Actual_Recipe_Parameters._FillingValveHead_SP := 0.000000e+00;
Actual_Recipe_Parameters._FirstProdExtraCO2Fact := 1.020000e+00;
Actual_Recipe_Parameters._GAS2_Injection := FALSE;
Actual_Recipe_Parameters._Gas2Fact := 0.000000e+00;
Actual_Recipe_Parameters._Gas2Vols := 0.000000e+00;
Actual_Recipe_Parameters._KFactRVM304BlowOff := 0.000000e+00;
Actual_Recipe_Parameters._Name := '';
Actual_Recipe_Parameters._PrdTankMinLevel := 3.500000e+01;
Actual_Recipe_Parameters._ProdBoosterPumpPress := 0.000000e+00;
Actual_Recipe_Parameters._ProdBrixOffset := 2.500000e-01;
Actual_Recipe_Parameters._ProdHighCond := 0.000000e+00;
Actual_Recipe_Parameters._ProdLowCond := 0.000000e+00;
Actual_Recipe_Parameters._ProdMeterHighBrix := 1.030000e+01;
Actual_Recipe_Parameters._ProdMeterHighCO2 := 2.900000e+00;
Actual_Recipe_Parameters._ProdMeterLowBrix := 9.830000e+00;
Actual_Recipe_Parameters._ProdMeterLowCO2 := 2.300000e+00;
Actual_Recipe_Parameters._ProdMeterRecipeNum := 1;
Actual_Recipe_Parameters._ProdMeter_ZeroBrix := 0.000000e+00;
Actual_Recipe_Parameters._ProdMeter_ZeroCO2 := 0.000000e+00;
Actual_Recipe_Parameters._ProdRecircPumpFreq := 0.000000e+00;
Actual_Recipe_Parameters._ProdSendPumpFreq := 0.000000e+00;
Actual_Recipe_Parameters._ProdTankPress := 4.400000e+00;
Actual_Recipe_Parameters._ProductBrix := 1.000000e+01;
Actual_Recipe_Parameters._ProductionRate := 3.800000e+02;
Actual_Recipe_Parameters._Ratio := 4.238896e+00;
Actual_Recipe_Parameters._SP_ProdTemp := 1.700000e+01;
Actual_Recipe_Parameters._SyrFlushing := FALSE;
Actual_Recipe_Parameters._SyrMeter_ZeroBrix := 0.000000e+00;
Actual_Recipe_Parameters._SyrupBrix := 4.625000e+01;
Actual_Recipe_Parameters._SyrupDensity := 1.206908e+00;
Actual_Recipe_Parameters._SyrupFactor := 1.000000e+00;
Actual_Recipe_Parameters._SyrupPumpPressure := 0.000000e+00;
Actual_Recipe_Parameters._SyrupValveSave := 0.000000e+00;
Actual_Recipe_Parameters._Type := 2;
Actual_Recipe_Parameters._WaterPumpPressure := 0.000000e+00;
Actual_Recipe_Parameters._WaterSelection := B#16#0;
Actual_Recipe_Parameters._WaterValveSave := 0.000000e+00;
Next_Recipe_Name := 'cambio 1$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00';
Next_Recipe_Number := 0;
ProcessSetup.Spare000 := 0.000000e+00;
ProcessSetup.Spare040 := 0.000000e+00;
ProcessSetup._AVN301_Nozzle_Kv := 1.650000e+02;
ProcessSetup._AVN302_Nozzle_Kv := 2.600000e+02;
ProcessSetup._AVN303_Nozzle_Kv := 1.650000e+02;
ProcessSetup._BaialageRVM301OVMax := 2.000000e+01;
ProcessSetup._BaialageRVM301OVMin := 2.000000e+00;
ProcessSetup._CIP2StepTM301Lvl := 0.000000e+00;
ProcessSetup._CIP2StepTN301Lvl := 0.000000e+00;
ProcessSetup._CIP2StepTP301Lvl := 0.000000e+00;
ProcessSetup._CIPPPM303Freq := 5.000000e+01;
ProcessSetup._CIPPPM306Freq := 5.000000e+00;
ProcessSetup._CIPPPM307Freq := 3.000000e+01;
ProcessSetup._CIPPPN301Freq := 5.000000e+00;
ProcessSetup._CIPPPP302Freq := 5.000000e+00;
ProcessSetup._CIPRMM301OV := 1.000000e+01;
ProcessSetup._CIPRMP302OV := 1.500000e+01;
ProcessSetup._CIPTM301MaxLevel := 5.500000e+01;
ProcessSetup._CIPTM301MinLevel := 3.500000e+01;
ProcessSetup._CIPTN301MaxLevel := 6.000000e+01;
ProcessSetup._CIPTN301MinLevel := 3.500000e+01;
ProcessSetup._CIPTP301MaxLevel := 4.500000e+01;
ProcessSetup._CIPTP301MinLevel := 2.500000e+01;
ProcessSetup._CarboCO2Pressure := 1.250000e+01;
ProcessSetup._DeoxSpryball_Kv := 6.700000e+01;
ProcessSetup._DiffSensor_DeltaHeight := -2.500000e+01;
ProcessSetup._DiffSensor_Height := 3.950000e+02;
ProcessSetup._DiffSensor_Offset := 3.618000e+01;
ProcessSetup._DrainTM301Flushing := 1.300000e+00;
ProcessSetup._DrainTM301Press := 1.000000e+00;
ProcessSetup._EndProdLastSyrlt := 0.000000e+00;
ProcessSetup._FastChgOvrTM301DrnPrss := 9.000000e-01;
ProcessSetup._FillerDiameter := 2.520000e+03;
ProcessSetup._FillerProdPipeDN := 1.000000e+02;
ProcessSetup._FillerProdPipeMass := 1.600000e+02;
ProcessSetup._FillingTime := 3.200000e+00;
ProcessSetup._FillingValveHeight := 1.400000e+03;
ProcessSetup._FillingValveNum := 91;
ProcessSetup._FirstProdDietExtraSyr := 1.400000e-03;
ProcessSetup._FirstProdExtraBrix := 5.000000e-02;
ProcessSetup._GAS2InjectionPress := 4.000000e+00;
ProcessSetup._H2OSerpPrimingVolume := 1.500000e+02;
ProcessSetup._ICS_AcidPulseWeight := 10;
ProcessSetup._ICS_CausticPulseWeight := 10;
ProcessSetup._ICS_ConcDosPausTimeAcid := 30;
ProcessSetup._ICS_ConcDosPausTimeCaus := 30;
ProcessSetup._ICS_ConcDosWorkTimeAcid := 30;
ProcessSetup._ICS_ConcDosWorkTimeCaus := 30;
ProcessSetup._ICS_PAAPulseWeight := 10;
ProcessSetup._ICS_VolDosPauseTimeAcid := 30;
ProcessSetup._ICS_VolDosPauseTimeCaus := 30;
ProcessSetup._ICS_VolDosWorkTimeAcid := 30;
ProcessSetup._ICS_VolDosWorkTimeCaus := 30;
ProcessSetup._ICS_VolDosWorkTimePAA := 30;
ProcessSetup._ICS_VolPauseTimePAA := 30;
ProcessSetup._ICS_VolumeRestOfLine := 3.500000e+02;
ProcessSetup._InjCO2Press_MaxFlow := 2.500000e+03;
ProcessSetup._InjCO2Press_MinFlow := 4.500000e+02;
ProcessSetup._InjCO2Press_Offset := 5.000000e-01;
ProcessSetup._KPPM303 := 5.700000e+00;
ProcessSetup._KProdLoss := 1.390000e-02;
ProcessSetup._KRecBlendError := 2.000000e+00;
ProcessSetup._KRecCarboCO2Error := 2.000000e+00;
ProcessSetup._KSyrupLoss := 7.800000e-03;
ProcessSetup._KWaterLoss := 1.000000e-03;
ProcessSetup._MaxBlendError := 1.000000e+02;
ProcessSetup._MaxCarboCO2Error := 5.000000e+02;
ProcessSetup._MinSpeedNominalProd := 4.000000e-01;
ProcessSetup._MinSpeedSlowProd := 3.000000e-01;
ProcessSetup._N2MinPressure := 1.000000e+00;
ProcessSetup._PPM307_H_MaxFlow := 0.000000e+00;
ProcessSetup._PPM307_H_MinFlow := 0.000000e+00;
ProcessSetup._PPM307_MaxFlow := 0.000000e+00;
ProcessSetup._PPM307_MinFlow := 0.000000e+00;
ProcessSetup._PPN301_H_MaxFlow := 9.000000e+01;
ProcessSetup._PPN301_H_MinFlow := 8.700000e+01;
ProcessSetup._PPN301_MaxFlow := 5.070000e+02;
ProcessSetup._PPN301_MinFlow := 2.110000e+02;
ProcessSetup._PPP302_H_MaxFlow := 8.600000e+01;
ProcessSetup._PPP302_H_MinFlow := 8.500000e+01;
ProcessSetup._PPP302_MaxFlow := 1.150000e+02;
ProcessSetup._PPP302_MinFlow := 3.200000e+01;
ProcessSetup._PercSyrupBrixSyrStarUp := 2.500000e+01;
ProcessSetup._PremixedLineDrainTime := 300;
ProcessSetup._ProdPPN304Freq := 5.000000e+01;
ProcessSetup._ProdPipeRunOutAmount := 3.000000e+01;
ProcessSetup._ProdPipeRunOutSt0Time := W#16#1;
ProcessSetup._PumpNominalFreq := 5.000000e+01;
ProcessSetup._RMM301ProdPipeRunOu := 3.000000e+01;
ProcessSetup._RMP302ProdPipeRunOu := 4.000000e+01;
ProcessSetup._RVN304Factor := 1.000000e+00;
ProcessSetup._RefTempCoolingCTRL := 0.000000e+00;
ProcessSetup._RinsePPM303Freq := 5.000000e+01;
ProcessSetup._RinsePPM306Freq := 5.000000e+00;
ProcessSetup._RinsePPM307Freq := 3.000000e+01;
ProcessSetup._RinsePPN301Freq := 5.000000e+00;
ProcessSetup._RinsePPP302Freq := 5.000000e+00;
ProcessSetup._RinseRMM301OV := 1.000000e+01;
ProcessSetup._RinseRMP302OV := 1.400000e+01;
ProcessSetup._RinseTM301Press := 3.000000e-01;
ProcessSetup._StartUpBrixExtraWater := 4.700000e+01;
ProcessSetup._StartUpCO2ExtraWater := 8.000000e+00;
ProcessSetup._StartUpPPM303Freq := 2.000000e+01;
ProcessSetup._SyrupLinePressure := 2.200000e+00;
ProcessSetup._SyrupRoomTank := 1;
ProcessSetup._SyrupRunOutLiters := 2.900000e+02;
ProcessSetup._T1_VacuumCtrl := L#1500;
ProcessSetup._T2_VacuumCtrl := L#1500;
ProcessSetup._T3_VacuumCtrl := L#1000;
ProcessSetup._T4_VacuumCtrl := L#1000;
ProcessSetup._TM301DrainSt0Time := W#16#A;
ProcessSetup._TM301DrainSt1Time := W#16#50;
ProcessSetup._TM301Height_0 := 1.050000e+03;
ProcessSetup._TM301Height_2 := 1.625000e+03;
ProcessSetup._TM301LevelPerc_2 := 4.600000e+01;
ProcessSetup._TM301RunOutChiller := 5.000000e+00;
ProcessSetup._Temp0_VacuumCtrl := 1.800000e+01;
ProcessSetup._Temp1_VacuumCtrl := 2.000000e+00;
ProcessSetup._Temp2_VacuumCtrl := 2.000000e+00;
ProcessSetup._Temp3_VacuumCtrl := 5.000000e+01;
ProcessSetup._Temp4_VacuumCtrl := 5.000000e+01;
Processor_Options.Blender_OPT.Spare101 := FALSE;
Processor_Options.Blender_OPT.Spare303 := FALSE;
Processor_Options.Blender_OPT._2ndOutlet := 0;
Processor_Options.Blender_OPT._Balaiage := FALSE;
Processor_Options.Blender_OPT._BlendFillSystem := TRUE;
Processor_Options.Blender_OPT._BrixMeter := TRUE;
Processor_Options.Blender_OPT._CIPHeatType := 0;
Processor_Options.Blender_OPT._CIPSignalExchange := FALSE;
Processor_Options.Blender_OPT._CO2InletMeter := TRUE;
Processor_Options.Blender_OPT._CO2_GAS2_Injection := FALSE;
Processor_Options.Blender_OPT._CO2_Offset := 4.500000e-01;
Processor_Options.Blender_OPT._CO2_SterileFilter := TRUE;
Processor_Options.Blender_OPT._CarboPresent := TRUE;
Processor_Options.Blender_OPT._ChillerCTRL := FALSE;
Processor_Options.Blender_OPT._CoolerControl := 4;
Processor_Options.Blender_OPT._CoolerPresent := TRUE;
Processor_Options.Blender_OPT._CoolerType := 0;
Processor_Options.Blender_OPT._CopressedAirInletMeter := FALSE;
Processor_Options.Blender_OPT._DBC_Type := FALSE;
Processor_Options.Blender_OPT._DeairPreMixed := FALSE;
Processor_Options.Blender_OPT._Deaireation := TRUE;
Processor_Options.Blender_OPT._DoubleDeair := TRUE;
Processor_Options.Blender_OPT._EHS_NrRes := 6;
Processor_Options.Blender_OPT._EthernetCom_CpuPN_CP := TRUE;
Processor_Options.Blender_OPT._FastChangeOverEnabled := TRUE;
Processor_Options.Blender_OPT._Flooding_Start_Up := FALSE;
Processor_Options.Blender_OPT._FlowMeterType := TRUE;
Processor_Options.Blender_OPT._GAS2InjectionType := 0;
Processor_Options.Blender_OPT._HistoricalTrends := TRUE;
Processor_Options.Blender_OPT._ICS_CustomerChemRecov := FALSE;
Processor_Options.Blender_OPT._ICS_CustomerChemicals := FALSE;
Processor_Options.Blender_OPT._ICS_CustomerH2ORecov := FALSE;
Processor_Options.Blender_OPT._ICS_CustomerHotWater := FALSE;
Processor_Options.Blender_OPT._InjectionPress_Ctrl := 1;
Processor_Options.Blender_OPT._InverterBoostPumpPPM307 := FALSE;
Processor_Options.Blender_OPT._InverterProdPumpPPM303 := FALSE;
Processor_Options.Blender_OPT._InverterRecirPumpPPM306 := FALSE;
Processor_Options.Blender_OPT._InverterSyrupPumpPPP302 := FALSE;
Processor_Options.Blender_OPT._InverterVacuuPumpPPN304 := FALSE;
Processor_Options.Blender_OPT._InverterWaterPumpPPN301 := FALSE;
Processor_Options.Blender_OPT._LocalCIP := FALSE;
Processor_Options.Blender_OPT._ManifoldSetting := TRUE;
Processor_Options.Blender_OPT._MaxSyrDeltaBrix := 8.000000e-01;
Processor_Options.Blender_OPT._MeterReceiveOnly := FALSE;
Processor_Options.Blender_OPT._MeterType := 6;
Processor_Options.Blender_OPT._ModelNum := 6; Processor_Options.Blender_OPT._ModelNum := 6;
Processor_Options.Blender_OPT._PAmPDSType := FALSE; Processor_Options.Blender_OPT._CO2_Offset := 4.500000e-01;
Processor_Options.Blender_OPT._PowerMeter := FALSE; Processor_Options.Blender_OPT._MaxSyrDeltaBrix := 8.000000e-01;
Processor_Options.Blender_OPT._ProdPressReleaseRVM304 := FALSE; Processor_Options.Blender_OPT._BrixMeter := TRUE;
Processor_Options.Blender_OPT._ProdPressureType := 0; Processor_Options.Blender_OPT.Spare101 := FALSE;
Processor_Options.Blender_OPT._ProductConductimeter := FALSE;
Processor_Options.Blender_OPT._ProductCoolingCTRL := FALSE;
Processor_Options.Blender_OPT._ProductO2Meter := FALSE;
Processor_Options.Blender_OPT._Promass := 2;
Processor_Options.Blender_OPT._PumpsSafetySwitches := FALSE;
Processor_Options.Blender_OPT._Report := TRUE;
Processor_Options.Blender_OPT._RunOut_Water := TRUE;
Processor_Options.Blender_OPT._SidelCip := FALSE;
Processor_Options.Blender_OPT._SidelFiller := FALSE;
Processor_Options.Blender_OPT._SignalExchange := 1;
Processor_Options.Blender_OPT._Simulation := FALSE;
Processor_Options.Blender_OPT._StillWaterByPass := FALSE;
Processor_Options.Blender_OPT._SurgeProtectionAct := FALSE;
Processor_Options.Blender_OPT._SyrBrixMeter := FALSE;
Processor_Options.Blender_OPT._TrackFillerSpeed := TRUE;
Processor_Options.Blender_OPT._TrackH2OEnable := FALSE; Processor_Options.Blender_OPT._TrackH2OEnable := FALSE;
Processor_Options.Blender_OPT._VacuumPump := 1; Processor_Options.Blender_OPT._PAmPDSType := FALSE;
Processor_Options.Blender_OPT._HistoricalTrends := TRUE;
Processor_Options.Blender_OPT._PowerMeter := FALSE;
Processor_Options.Blender_OPT._Report := TRUE;
Processor_Options.Blender_OPT._Balaiage := FALSE;
Processor_Options.Blender_OPT._Valves_FullFeedback := TRUE; Processor_Options.Blender_OPT._Valves_FullFeedback := TRUE;
Processor_Options.Blender_OPT._Valves_SingleFeedback := FALSE; Processor_Options.Blender_OPT._Valves_SingleFeedback := FALSE;
Processor_Options.Blender_OPT._PumpsSafetySwitches := FALSE;
Processor_Options.Blender_OPT._SurgeProtectionAct := FALSE;
Processor_Options.Blender_OPT._DBC_Type := FALSE;
Processor_Options.Blender_OPT._CO2InletMeter := TRUE;
Processor_Options.Blender_OPT._ProductO2Meter := FALSE;
Processor_Options.Blender_OPT._CopressedAirInletMeter := FALSE;
Processor_Options.Blender_OPT._MeterType := 6;
Processor_Options.Blender_OPT._MeterReceiveOnly := FALSE;
Processor_Options.Blender_OPT._SyrBrixMeter := FALSE;
Processor_Options.Blender_OPT._Flooding_Start_Up := FALSE;
Processor_Options.Blender_OPT._FastChangeOverEnabled := TRUE;
Processor_Options.Blender_OPT._WaterInletMeter := FALSE; Processor_Options.Blender_OPT._WaterInletMeter := FALSE;
Processor_Options.Blender_OPT._BlendFillSystem := TRUE;
Processor_Options.Blender_OPT._TrackFillerSpeed := TRUE;
Processor_Options.Blender_OPT._SignalExchange := 1;
Processor_Options.Blender_OPT._CoolerPresent := TRUE;
Processor_Options.Blender_OPT._CoolerControl := 4;
Processor_Options.Blender_OPT._CoolerType := 0;
Processor_Options.Blender_OPT._LocalCIP := FALSE;
Processor_Options.Blender_OPT._ICS_CustomerHotWater := FALSE;
Processor_Options.Blender_OPT._ICS_CustomerChemRecov := FALSE;
Processor_Options.Blender_OPT._CIPSignalExchange := FALSE;
Processor_Options.Blender_OPT._ICS_CustomerChemicals := FALSE;
Processor_Options.Blender_OPT._CarboPresent := TRUE;
Processor_Options.Blender_OPT._InverterSyrupPumpPPP302 := FALSE;
Processor_Options.Blender_OPT._InverterWaterPumpPPN301 := FALSE;
Processor_Options.Blender_OPT._DoubleDeair := TRUE;
Processor_Options.Blender_OPT._DeairPreMixed := FALSE;
Processor_Options.Blender_OPT._Deaireation := TRUE;
Processor_Options.Blender_OPT._StillWaterByPass := FALSE;
Processor_Options.Blender_OPT._ManifoldSetting := TRUE;
Processor_Options.Blender_OPT._InverterProdPumpPPM303 := FALSE;
Processor_Options.Blender_OPT._SidelCip := FALSE;
Processor_Options.Blender_OPT._EthernetCom_CpuPN_CP := TRUE;
Processor_Options.Blender_OPT._2ndOutlet := 0;
Processor_Options.Blender_OPT._Promass := 2;
Processor_Options.Blender_OPT._WaterPromass := TRUE; Processor_Options.Blender_OPT._WaterPromass := TRUE;
Processor_Options.Blender_OPT._ProductConductimeter := FALSE;
Processor_Options.Blender_OPT._ICS_CustomerH2ORecov := FALSE;
Processor_Options.Blender_OPT.Spare303 := FALSE;
Processor_Options.Blender_OPT._CO2_GAS2_Injection := FALSE;
Processor_Options.Blender_OPT._InverterVacuuPumpPPN304 := FALSE;
Processor_Options.Blender_OPT._InverterBoostPumpPPM307 := FALSE;
Processor_Options.Blender_OPT._RunOut_Water := TRUE;
Processor_Options.Blender_OPT._FlowMeterType := TRUE;
Processor_Options.Blender_OPT._SidelFiller := FALSE;
Processor_Options.Blender_OPT._Simulation := FALSE;
Processor_Options.Blender_OPT._ProductCoolingCTRL := FALSE;
Processor_Options.Blender_OPT._ChillerCTRL := FALSE;
Processor_Options.Blender_OPT._CO2_SterileFilter := TRUE;
Processor_Options.Blender_OPT._InverterRecirPumpPPM306 := FALSE;
Processor_Options.Blender_OPT._ProdPressReleaseRVM304 := FALSE;
Processor_Options.Blender_OPT._VacuumPump := 1;
Processor_Options.Blender_OPT._GAS2InjectionType := 0;
Processor_Options.Blender_OPT._InjectionPress_Ctrl := 1;
Processor_Options.Blender_OPT._ProdPressureType := 0;
Processor_Options.Blender_OPT._CIPHeatType := 0;
Processor_Options.Blender_OPT._EHS_NrRes := 6;
Spare1[1] := 0; Spare1[1] := 0;
Spare1[2] := 0; Spare1[2] := 0;
Spare1[3] := 0; Spare1[3] := 0;
@ -523,20 +351,65 @@ BEGIN
Spare1[7] := 0; Spare1[7] := 0;
Spare1[8] := 0; Spare1[8] := 0;
Spare1[9] := 0; Spare1[9] := 0;
_RVM301_DeadBand := 5.000000e-02;
_RVM301_Kp := 9.000000e+01;
Actual_Recipe_Parameters._Name := '';
Actual_Recipe_Parameters._EnProdTemp := TRUE;
Actual_Recipe_Parameters._SyrFlushing := FALSE;
Actual_Recipe_Parameters._GAS2_Injection := FALSE;
Actual_Recipe_Parameters._Eq_Pression_Selected := FALSE;
Actual_Recipe_Parameters._DeoxStripEn := FALSE;
Actual_Recipe_Parameters._DeoxVacuumEn := TRUE;
Actual_Recipe_Parameters._DeoxPreMixed := FALSE;
Actual_Recipe_Parameters._EnBlowOffProdPipeCO2Fil := FALSE;
Actual_Recipe_Parameters._WaterSelection := B#16#0;
Actual_Recipe_Parameters._FillerNextRecipeNum := B#16#0;
Actual_Recipe_Parameters._BottleShape := B#16#0;
Actual_Recipe_Parameters._Type := 2;
Actual_Recipe_Parameters._ProdMeterRecipeNum := 1;
Actual_Recipe_Parameters._SyrupBrix := 4.625000e+01;
Actual_Recipe_Parameters._SyrupDensity := 1.206908e+00;
Actual_Recipe_Parameters._SyrupFactor := 1.000000e+00;
Actual_Recipe_Parameters._ProductBrix := 1.000000e+01;
Actual_Recipe_Parameters._ProductionRate := 3.800000e+02;
Actual_Recipe_Parameters._Ratio := 4.238896e+00;
Actual_Recipe_Parameters._ProdBrixOffset := 2.500000e-01;
Actual_Recipe_Parameters._CO2Vols := 2.550000e+00;
Actual_Recipe_Parameters._CO2Fact := 9.400000e-01;
Actual_Recipe_Parameters._ProdTankPress := 4.400000e+00;
Actual_Recipe_Parameters._SP_ProdTemp := 1.700000e+01;
Actual_Recipe_Parameters._PrdTankMinLevel := 3.500000e+01;
Actual_Recipe_Parameters._WaterValveSave := 0.000000e+00;
Actual_Recipe_Parameters._SyrupValveSave := 0.000000e+00;
Actual_Recipe_Parameters._CarboCO2ValveSave := 0.000000e+00;
Actual_Recipe_Parameters._ProdMeterHighBrix := 1.030000e+01;
Actual_Recipe_Parameters._ProdMeterLowBrix := 9.830000e+00;
Actual_Recipe_Parameters._ProdMeterHighCO2 := 2.900000e+00;
Actual_Recipe_Parameters._ProdMeterLowCO2 := 2.300000e+00;
Actual_Recipe_Parameters._ProdMeter_ZeroCO2 := 0.000000e+00;
Actual_Recipe_Parameters._ProdMeter_ZeroBrix := 0.000000e+00;
Actual_Recipe_Parameters._ProdHighCond := 0.000000e+00;
Actual_Recipe_Parameters._ProdLowCond := 0.000000e+00;
Actual_Recipe_Parameters._BottleSize := 0.000000e+00;
Actual_Recipe_Parameters._FillingValveHead_SP := 0.000000e+00;
Actual_Recipe_Parameters._SyrMeter_ZeroBrix := 0.000000e+00;
Actual_Recipe_Parameters._FirstProdExtraCO2Fact := 1.020000e+00;
Actual_Recipe_Parameters._Gas2Vols := 0.000000e+00;
Actual_Recipe_Parameters._Gas2Fact := 0.000000e+00;
Actual_Recipe_Parameters._SyrupPumpPressure := 0.000000e+00;
Actual_Recipe_Parameters._WaterPumpPressure := 0.000000e+00;
Actual_Recipe_Parameters._CO2_Air_N2_PressSelect := 0;
Actual_Recipe_Parameters._KFactRVM304BlowOff := 0.000000e+00;
Actual_Recipe_Parameters._ProdRecircPumpFreq := 0.000000e+00;
Actual_Recipe_Parameters._ProdBoosterPumpPress := 0.000000e+00;
Actual_Recipe_Parameters._ProdSendPumpFreq := 0.000000e+00;
Spare2[1] := 0; Spare2[1] := 0;
Spare2[2] := 0; Spare2[2] := 0;
Spare2[3] := 0; Spare2[3] := 0;
Spare2[4] := 0; Spare2[4] := 0;
Spare2[5] := 0; Spare2[5] := 0;
Spare3[10] := 0; Next_Recipe_Name := 'cambio 1$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00';
Spare3[11] := 0; Next_Recipe_Number := 0;
Spare3[12] := 0;
Spare3[13] := 0;
Spare3[14] := 0;
Spare3[15] := 0;
Spare3[16] := 0;
Spare3[17] := 0;
Spare3[18] := 0;
Spare3[1] := 0; Spare3[1] := 0;
Spare3[2] := 0; Spare3[2] := 0;
Spare3[3] := 0; Spare3[3] := 0;
@ -546,8 +419,136 @@ BEGIN
Spare3[7] := 0; Spare3[7] := 0;
Spare3[8] := 0; Spare3[8] := 0;
Spare3[9] := 0; Spare3[9] := 0;
_RVM301_DeadBand := 5.000000e-02; Spare3[10] := 0;
_RVM301_Kp := 9.000000e+01; Spare3[11] := 0;
Spare3[12] := 0;
Spare3[13] := 0;
Spare3[14] := 0;
Spare3[15] := 0;
Spare3[16] := 0;
Spare3[17] := 0;
Spare3[18] := 0;
ProcessSetup.Spare000 := 0.000000e+00;
ProcessSetup.Spare040 := 0.000000e+00;
ProcessSetup._KWaterLoss := 1.000000e-03;
ProcessSetup._KSyrupLoss := 7.800000e-03;
ProcessSetup._KProdLoss := 1.390000e-02;
ProcessSetup._KPPM303 := 5.700000e+00;
ProcessSetup._BaialageRVM301OVMin := 2.000000e+00;
ProcessSetup._SyrupLinePressure := 2.200000e+00;
ProcessSetup._CIPRMM301OV := 1.000000e+01;
ProcessSetup._CIPRMP302OV := 1.500000e+01;
ProcessSetup._CIPTM301MinLevel := 3.500000e+01;
ProcessSetup._CIPTM301MaxLevel := 5.500000e+01;
ProcessSetup._CIPPPM303Freq := 5.000000e+01;
ProcessSetup._CIPTP301MinLevel := 2.500000e+01;
ProcessSetup._CIPTP301MaxLevel := 4.500000e+01;
ProcessSetup._RinseRMM301OV := 1.000000e+01;
ProcessSetup._RinseRMP302OV := 1.400000e+01;
ProcessSetup._RinseTM301Press := 3.000000e-01;
ProcessSetup._RinsePPM303Freq := 5.000000e+01;
ProcessSetup._DrainTM301Press := 1.000000e+00;
ProcessSetup._KRecBlendError := 2.000000e+00;
ProcessSetup._KRecCarboCO2Error := 2.000000e+00;
ProcessSetup._MaxBlendError := 1.000000e+02;
ProcessSetup._MaxCarboCO2Error := 5.000000e+02;
ProcessSetup._StartUpBrixExtraWater := 4.700000e+01;
ProcessSetup._StartUpCO2ExtraWater := 8.000000e+00;
ProcessSetup._StartUpPPM303Freq := 2.000000e+01;
ProcessSetup._SyrupRoomTank := 1;
ProcessSetup._SyrupRunOutLiters := 2.900000e+02;
ProcessSetup._InjCO2Press_Offset := 5.000000e-01;
ProcessSetup._InjCO2Press_MinFlow := 4.500000e+02;
ProcessSetup._InjCO2Press_MaxFlow := 2.500000e+03;
ProcessSetup._CarboCO2Pressure := 1.250000e+01;
ProcessSetup._N2MinPressure := 1.000000e+00;
ProcessSetup._DiffSensor_Height := 3.950000e+02;
ProcessSetup._DiffSensor_DeltaHeight := -2.500000e+01;
ProcessSetup._DiffSensor_Offset := 3.618000e+01;
ProcessSetup._FillingValveHeight := 1.400000e+03;
ProcessSetup._FillerDiameter := 2.520000e+03;
ProcessSetup._FillingValveNum := 91;
ProcessSetup._FillerProdPipeDN := 1.000000e+02;
ProcessSetup._FillerProdPipeMass := 1.600000e+02;
ProcessSetup._FillingTime := 3.200000e+00;
ProcessSetup._TM301Height_0 := 1.050000e+03;
ProcessSetup._TM301LevelPerc_2 := 4.600000e+01;
ProcessSetup._TM301Height_2 := 1.625000e+03;
ProcessSetup._RVN304Factor := 1.000000e+00;
ProcessSetup._DrainTM301Flushing := 1.300000e+00;
ProcessSetup._FirstProdExtraBrix := 5.000000e-02;
ProcessSetup._FirstProdDietExtraSyr := 1.400000e-03;
ProcessSetup._EndProdLastSyrlt := 0.000000e+00;
ProcessSetup._TM301DrainSt0Time := W#16#A;
ProcessSetup._TM301DrainSt1Time := W#16#50;
ProcessSetup._ProdPipeRunOutSt0Time := W#16#1;
ProcessSetup._RMM301ProdPipeRunOu := 3.000000e+01;
ProcessSetup._RMP302ProdPipeRunOu := 4.000000e+01;
ProcessSetup._ProdPipeRunOutAmount := 3.000000e+01;
ProcessSetup._TM301RunOutChiller := 5.000000e+00;
ProcessSetup._MinSpeedNominalProd := 4.000000e-01;
ProcessSetup._MinSpeedSlowProd := 3.000000e-01;
ProcessSetup._FastChgOvrTM301DrnPrss := 9.000000e-01;
ProcessSetup._CIPTN301MinLevel := 3.500000e+01;
ProcessSetup._CIPTN301MaxLevel := 6.000000e+01;
ProcessSetup._ProdPPN304Freq := 5.000000e+01;
ProcessSetup._GAS2InjectionPress := 4.000000e+00;
ProcessSetup._BaialageRVM301OVMax := 2.000000e+01;
ProcessSetup._RinsePPN301Freq := 5.000000e+00;
ProcessSetup._CIPPPN301Freq := 5.000000e+00;
ProcessSetup._RinsePPP302Freq := 5.000000e+00;
ProcessSetup._CIPPPP302Freq := 5.000000e+00;
ProcessSetup._PercSyrupBrixSyrStarUp := 2.500000e+01;
ProcessSetup._RefTempCoolingCTRL := 0.000000e+00;
ProcessSetup._H2OSerpPrimingVolume := 1.500000e+02;
ProcessSetup._AVN301_Nozzle_Kv := 1.650000e+02;
ProcessSetup._AVN302_Nozzle_Kv := 2.600000e+02;
ProcessSetup._AVN303_Nozzle_Kv := 1.650000e+02;
ProcessSetup._DeoxSpryball_Kv := 6.700000e+01;
ProcessSetup._PremixedLineDrainTime := 300;
ProcessSetup._PPN301_H_MaxFlow := 9.000000e+01;
ProcessSetup._PPN301_H_MinFlow := 8.700000e+01;
ProcessSetup._PPN301_MaxFlow := 5.070000e+02;
ProcessSetup._PPN301_MinFlow := 2.110000e+02;
ProcessSetup._PPP302_H_MaxFlow := 8.600000e+01;
ProcessSetup._PPP302_H_MinFlow := 8.500000e+01;
ProcessSetup._PPP302_MaxFlow := 1.150000e+02;
ProcessSetup._PPP302_MinFlow := 3.200000e+01;
ProcessSetup._RinsePPM306Freq := 5.000000e+00;
ProcessSetup._CIPPPM306Freq := 5.000000e+00;
ProcessSetup._PPM307_H_MaxFlow := 0.000000e+00;
ProcessSetup._PPM307_H_MinFlow := 0.000000e+00;
ProcessSetup._PPM307_MaxFlow := 0.000000e+00;
ProcessSetup._PPM307_MinFlow := 0.000000e+00;
ProcessSetup._Temp0_VacuumCtrl := 1.800000e+01;
ProcessSetup._Temp1_VacuumCtrl := 2.000000e+00;
ProcessSetup._Temp2_VacuumCtrl := 2.000000e+00;
ProcessSetup._Temp3_VacuumCtrl := 5.000000e+01;
ProcessSetup._Temp4_VacuumCtrl := 5.000000e+01;
ProcessSetup._T1_VacuumCtrl := L#1500;
ProcessSetup._T2_VacuumCtrl := L#1500;
ProcessSetup._T3_VacuumCtrl := L#1000;
ProcessSetup._T4_VacuumCtrl := L#1000;
ProcessSetup._ICS_VolDosWorkTimePAA := 30;
ProcessSetup._ICS_VolPauseTimePAA := 30;
ProcessSetup._ICS_PAAPulseWeight := 10;
ProcessSetup._ICS_CausticPulseWeight := 10;
ProcessSetup._ICS_AcidPulseWeight := 10;
ProcessSetup._ICS_VolumeRestOfLine := 3.500000e+02;
ProcessSetup._ICS_VolDosWorkTimeCaus := 30;
ProcessSetup._ICS_VolDosPauseTimeCaus := 30;
ProcessSetup._ICS_VolDosWorkTimeAcid := 30;
ProcessSetup._ICS_VolDosPauseTimeAcid := 30;
ProcessSetup._ICS_ConcDosWorkTimeCaus := 30;
ProcessSetup._ICS_ConcDosPausTimeCaus := 30;
ProcessSetup._ICS_ConcDosWorkTimeAcid := 30;
ProcessSetup._ICS_ConcDosPausTimeAcid := 30;
ProcessSetup._RinsePPM307Freq := 3.000000e+01;
ProcessSetup._CIPPPM307Freq := 3.000000e+01;
ProcessSetup._CIP2StepTN301Lvl := 0.000000e+00;
ProcessSetup._CIP2StepTM301Lvl := 0.000000e+00;
ProcessSetup._CIP2StepTP301Lvl := 0.000000e+00;
ProcessSetup._PumpNominalFreq := 5.000000e+01;
_SwitchOff_DensityOK := FALSE; _SwitchOff_DensityOK := FALSE;
END_DATA_BLOCK; END_DATA_BLOCK

View File

@ -0,0 +1,549 @@
DATA_BLOCK "HMI_Blender_Parameters"
TITLE = { S7_language := '28(1) Albanese 15.06.2005 17:07:04' }
FAMILY : Resource
VERSION : 0.0
STRUCT
STAT0 : STRUCT
STAT1 : STRUCT
STAT2 : INT := 6;
STAT3 : REAL := 2.000000e-01;
STAT4 : REAL := 8.000000e-01;
STAT5 : BOOL := TRUE;
STAT6 : BOOL;
STAT7 : BOOL;
STAT8 : BOOL;
STAT9 : BOOL;
STAT10 : BOOL;
STAT11 : BOOL := TRUE;
STAT12 : BOOL;
STAT13 : BOOL := TRUE;
STAT14 : BOOL;
STAT15 : BOOL;
STAT16 : BOOL;
STAT17 : BOOL;
STAT18 : BOOL := TRUE;
STAT19 : BOOL;
STAT20 : BOOL;
STAT21 : INT := 6;
STAT22 : BOOL;
STAT23 : BOOL;
STAT24 : BOOL;
STAT25 : BOOL;
STAT26 : BOOL;
STAT27 : BOOL := TRUE;
STAT28 : BOOL := TRUE;
STAT29 : INT := 1;
STAT30 : BOOL := TRUE;
STAT31 : INT := 4;
STAT32 : INT;
STAT33 : BOOL;
STAT34 : BOOL;
STAT35 : BOOL;
STAT36 : BOOL;
STAT37 : BOOL;
STAT38 : BOOL := TRUE;
STAT39 : BOOL;
STAT40 : BOOL;
STAT41 : BOOL := TRUE;
STAT42 : BOOL;
STAT43 : BOOL := TRUE;
STAT44 : BOOL;
STAT45 : BOOL := TRUE;
STAT46 : BOOL;
STAT47 : BOOL;
STAT48 : BOOL := TRUE;
STAT49 : INT;
STAT50 : INT := 2;
STAT51 : BOOL := TRUE;
STAT52 : BOOL;
STAT53 : BOOL;
STAT54 : BOOL;
STAT55 : BOOL;
STAT56 : BOOL;
STAT57 : BOOL;
STAT58 : BOOL := TRUE;
STAT59 : BOOL;
STAT60 : BOOL;
STAT61 : BOOL;
STAT62 : BOOL;
STAT63 : BOOL;
STAT64 : BOOL := TRUE;
STAT65 : BOOL;
STAT66 : BOOL;
STAT67 : INT := 1;
STAT68 : INT;
STAT69 : INT := 1;
STAT70 : INT;
STAT71 : INT;
STAT72 : INT := 6;
END_STRUCT;
END_STRUCT;
STAT73 : ARRAY [1..9] OF INT;
STAT74 : REAL := 5.000000e-02;
STAT75 : REAL := 6.500000e+01;
STAT76 : STRUCT
STAT77 : STRING[32] := ' ';
STAT78 : BOOL;
STAT79 : BOOL;
STAT80 : BOOL;
STAT81 : BOOL;
STAT82 : BOOL;
STAT83 : BOOL;
STAT84 : BOOL;
STAT85 : BOOL;
STAT86 : BYTE;
STAT87 : BYTE;
STAT88 : BYTE;
STAT89 : INT := 1;
STAT90 : INT;
STAT91 : REAL := 5.000000e+01;
STAT92 : REAL := 1.255800e+00;
STAT93 : REAL := 1.000000e+00;
STAT94 : REAL := 1.045000e+01;
STAT95 : REAL := 9.000000e+02;
STAT96 : REAL := 2.000000e+01;
STAT97 : REAL;
STAT98 : REAL;
STAT99 : REAL := 1.000000e+00;
STAT100 : REAL := 1.000000e+00;
STAT101 : REAL := 1.000000e+01;
STAT102 : REAL := 1.000000e+01;
STAT103 : REAL;
STAT104 : REAL;
STAT105 : REAL;
STAT106 : REAL;
STAT107 : REAL;
STAT108 : REAL;
STAT109 : REAL;
STAT110 : REAL;
STAT111 : REAL;
STAT112 : REAL;
STAT113 : REAL;
STAT114 : REAL;
STAT115 : REAL;
STAT116 : REAL;
STAT117 : REAL := 9.700000e-01;
STAT118 : REAL;
STAT119 : REAL := 1.000000e+00;
STAT120 : REAL;
STAT121 : REAL;
STAT122 : INT;
STAT123 : REAL;
STAT124 : REAL;
STAT125 : REAL;
STAT126 : REAL;
END_STRUCT;
STAT127 : ARRAY [1..5] OF INT;
STAT128 : STRING[32] := ' ';
STAT129 : INT;
STAT130 : ARRAY [1..18] OF INT;
STAT131 : STRUCT
STAT132 : REAL;
STAT133 : REAL;
STAT134 : REAL := 1.580000e-03;
STAT135 : REAL := 9.000000e-03;
STAT136 : REAL := 1.700000e-02;
STAT137 : REAL := 5.700000e+00;
STAT138 : REAL := 2.000000e+00;
STAT139 : REAL := 2.000000e+00;
STAT140 : REAL := 1.000000e+01;
STAT141 : REAL := 1.000000e+01;
STAT142 : REAL := 1.000000e+01;
STAT143 : REAL := 6.000000e+01;
STAT144 : REAL := 5.000000e+01;
STAT145 : REAL := 2.500000e+01;
STAT146 : REAL := 6.500000e+01;
STAT147 : REAL := 1.200000e+01;
STAT148 : REAL := 1.000000e+01;
STAT149 : REAL;
STAT150 : REAL := 3.000000e+01;
STAT151 : REAL := 1.000000e+00;
STAT152 : REAL := 5.000000e+00;
STAT153 : REAL := 5.000000e+00;
STAT154 : REAL := 1.000000e+02;
STAT155 : REAL := 2.000000e+02;
STAT156 : REAL := 2.000000e+01;
STAT157 : REAL := 2.000000e+01;
STAT158 : REAL := 2.000000e+01;
STAT159 : INT := 1;
STAT160 : REAL := 2.000000e+01;
STAT161 : REAL := 7.000000e-01;
STAT162 : REAL := 4.250000e+02;
STAT163 : REAL := 2.550000e+03;
STAT164 : REAL := 9.000000e+00;
STAT165 : REAL;
STAT166 : REAL := 1.600000e+03;
STAT167 : REAL := 2.000000e+01;
STAT168 : REAL := 1.400000e+01;
STAT169 : REAL := 1.610000e+03;
STAT170 : REAL := 2.877000e+03;
STAT171 : INT := 80;
STAT172 : REAL := 8.000000e+01;
STAT173 : REAL := 9.000000e+01;
STAT174 : REAL := 4.000000e+00;
STAT175 : REAL := 1.020000e+03;
STAT176 : REAL := 1.000000e+02;
STAT177 : REAL := 2.300000e+03;
STAT178 : REAL := 7.500000e-01;
STAT179 : REAL := 5.000000e-01;
STAT180 : REAL := 3.000000e-02;
STAT181 : REAL := 1.400000e-03;
STAT182 : REAL;
STAT183 : WORD := W#16#6;
STAT184 : WORD := W#16#50;
STAT185 : WORD := W#16#1;
STAT186 : REAL := 3.000000e+01;
STAT187 : REAL := 4.000000e+01;
STAT188 : REAL := 9.000000e+01;
STAT189 : REAL := 2.500000e+02;
STAT190 : REAL := 5.500000e-01;
STAT191 : REAL := 4.000000e-01;
STAT192 : REAL := 9.000000e-01;
STAT193 : REAL := 1.500000e+01;
STAT194 : REAL := 4.500000e+01;
STAT195 : REAL := 5.000000e+01;
STAT196 : REAL := 4.000000e+00;
STAT197 : REAL := 2.000000e+01;
STAT198 : REAL := 5.000000e+00;
STAT199 : REAL := 5.000000e+00;
STAT200 : REAL := 5.000000e+00;
STAT201 : REAL := 5.000000e+00;
STAT202 : REAL := 1.000000e+01;
STAT203 : REAL;
STAT204 : REAL := 1.150000e+02;
STAT205 : REAL := 1.650000e+02;
STAT206 : REAL := 2.600000e+02;
STAT207 : REAL := 1.650000e+02;
STAT208 : REAL := 6.700000e+01;
STAT209 : INT := 50;
STAT210 : REAL := 9.000000e+01;
STAT211 : REAL := 8.700000e+01;
STAT212 : REAL := 5.070000e+02;
STAT213 : REAL := 2.110000e+02;
STAT214 : REAL := 8.600000e+01;
STAT215 : REAL := 8.500000e+01;
STAT216 : REAL := 1.150000e+02;
STAT217 : REAL := 3.200000e+01;
STAT218 : REAL := 5.000000e+00;
STAT219 : REAL := 5.000000e+00;
STAT220 : REAL;
STAT221 : REAL;
STAT222 : REAL;
STAT223 : REAL;
STAT224 : REAL := 1.800000e+01;
STAT225 : REAL := 2.000000e+00;
STAT226 : REAL := 2.000000e+00;
STAT227 : REAL := 5.000000e+01;
STAT228 : REAL := 5.000000e+01;
STAT229 : DINT := L#1500;
STAT230 : DINT := L#1500;
STAT231 : DINT := L#1000;
STAT232 : DINT := L#1000;
STAT233 : INT := 30;
STAT234 : INT := 30;
STAT235 : INT := 10;
STAT236 : INT := 10;
STAT237 : INT := 10;
STAT238 : REAL := 3.500000e+02;
STAT239 : INT := 30;
STAT240 : INT := 30;
STAT241 : INT := 30;
STAT242 : INT := 30;
STAT243 : INT := 30;
STAT244 : INT := 30;
STAT245 : INT := 30;
STAT246 : INT := 30;
STAT247 : REAL := 3.000000e+01;
STAT248 : REAL := 3.000000e+01;
STAT249 : REAL;
STAT250 : REAL;
STAT251 : REAL;
STAT252 : REAL := 5.000000e+01;
END_STRUCT;
STAT253 : BOOL;
STAT254 : REAL;
END_STRUCT;
BEGIN
STAT0.STAT1.STAT2 := 6;
STAT0.STAT1.STAT3 := 4.500000e-01;
STAT0.STAT1.STAT4 := 8.000000e-01;
STAT0.STAT1.STAT5 := TRUE;
STAT0.STAT1.STAT6 := FALSE;
STAT0.STAT1.STAT7 := FALSE;
STAT0.STAT1.STAT8 := FALSE;
STAT0.STAT1.STAT9 := TRUE;
STAT0.STAT1.STAT10 := FALSE;
STAT0.STAT1.STAT11 := TRUE;
STAT0.STAT1.STAT12 := FALSE;
STAT0.STAT1.STAT13 := TRUE;
STAT0.STAT1.STAT14 := FALSE;
STAT0.STAT1.STAT15 := FALSE;
STAT0.STAT1.STAT16 := FALSE;
STAT0.STAT1.STAT17 := FALSE;
STAT0.STAT1.STAT18 := TRUE;
STAT0.STAT1.STAT19 := FALSE;
STAT0.STAT1.STAT20 := FALSE;
STAT0.STAT1.STAT21 := 6;
STAT0.STAT1.STAT22 := FALSE;
STAT0.STAT1.STAT23 := FALSE;
STAT0.STAT1.STAT24 := FALSE;
STAT0.STAT1.STAT25 := TRUE;
STAT0.STAT1.STAT26 := FALSE;
STAT0.STAT1.STAT27 := TRUE;
STAT0.STAT1.STAT28 := TRUE;
STAT0.STAT1.STAT29 := 1;
STAT0.STAT1.STAT30 := TRUE;
STAT0.STAT1.STAT31 := 4;
STAT0.STAT1.STAT32 := 0;
STAT0.STAT1.STAT33 := FALSE;
STAT0.STAT1.STAT34 := FALSE;
STAT0.STAT1.STAT35 := FALSE;
STAT0.STAT1.STAT36 := FALSE;
STAT0.STAT1.STAT37 := FALSE;
STAT0.STAT1.STAT38 := TRUE;
STAT0.STAT1.STAT39 := FALSE;
STAT0.STAT1.STAT40 := FALSE;
STAT0.STAT1.STAT41 := TRUE;
STAT0.STAT1.STAT42 := FALSE;
STAT0.STAT1.STAT43 := TRUE;
STAT0.STAT1.STAT44 := FALSE;
STAT0.STAT1.STAT45 := TRUE;
STAT0.STAT1.STAT46 := FALSE;
STAT0.STAT1.STAT47 := FALSE;
STAT0.STAT1.STAT48 := TRUE;
STAT0.STAT1.STAT49 := 0;
STAT0.STAT1.STAT50 := 2;
STAT0.STAT1.STAT51 := TRUE;
STAT0.STAT1.STAT52 := FALSE;
STAT0.STAT1.STAT53 := FALSE;
STAT0.STAT1.STAT54 := FALSE;
STAT0.STAT1.STAT55 := FALSE;
STAT0.STAT1.STAT56 := FALSE;
STAT0.STAT1.STAT57 := FALSE;
STAT0.STAT1.STAT58 := TRUE;
STAT0.STAT1.STAT59 := TRUE;
STAT0.STAT1.STAT60 := FALSE;
STAT0.STAT1.STAT61 := FALSE;
STAT0.STAT1.STAT62 := FALSE;
STAT0.STAT1.STAT63 := FALSE;
STAT0.STAT1.STAT64 := TRUE;
STAT0.STAT1.STAT65 := FALSE;
STAT0.STAT1.STAT66 := FALSE;
STAT0.STAT1.STAT67 := 1;
STAT0.STAT1.STAT68 := 0;
STAT0.STAT1.STAT69 := 1;
STAT0.STAT1.STAT70 := 0;
STAT0.STAT1.STAT71 := 0;
STAT0.STAT1.STAT72 := 6;
STAT73[1] := 0;
STAT73[2] := 0;
STAT73[3] := 0;
STAT73[4] := 0;
STAT73[5] := 0;
STAT73[6] := 0;
STAT73[7] := 0;
STAT73[8] := 0;
STAT73[9] := 0;
STAT74 := 5.000000e-02;
STAT75 := 9.000000e+01;
STAT76.STAT77 := '';
STAT76.STAT78 := TRUE;
STAT76.STAT79 := FALSE;
STAT76.STAT80 := FALSE;
STAT76.STAT81 := FALSE;
STAT76.STAT82 := FALSE;
STAT76.STAT83 := TRUE;
STAT76.STAT84 := FALSE;
STAT76.STAT85 := FALSE;
STAT76.STAT86 := B#16#0;
STAT76.STAT87 := B#16#14;
STAT76.STAT88 := B#16#0;
STAT76.STAT89 := 2;
STAT76.STAT90 := 1;
STAT76.STAT91 := 3.935000e+01;
STAT76.STAT92 := 1.166600e+00;
STAT76.STAT93 := 1.000000e+00;
STAT76.STAT94 := 8.600000e+00;
STAT76.STAT95 := 2.500000e-01;
STAT76.STAT96 := 3.934034e+00;
STAT76.STAT97 := 4.000000e-01;
STAT76.STAT98 := 2.500000e+00;
STAT76.STAT99 := 9.000000e-01;
STAT76.STAT100 := 3.500000e+00;
STAT76.STAT101 := 1.600000e+01;
STAT76.STAT102 := 3.500000e+01;
STAT76.STAT103 := 0.000000e+00;
STAT76.STAT104 := 0.000000e+00;
STAT76.STAT105 := 0.000000e+00;
STAT76.STAT106 := 8.800000e+00;
STAT76.STAT107 := 8.400000e+00;
STAT76.STAT108 := 2.800000e+00;
STAT76.STAT109 := 2.200000e+00;
STAT76.STAT110 := 0.000000e+00;
STAT76.STAT111 := 0.000000e+00;
STAT76.STAT112 := 0.000000e+00;
STAT76.STAT113 := 0.000000e+00;
STAT76.STAT114 := 0.000000e+00;
STAT76.STAT115 := 0.000000e+00;
STAT76.STAT116 := 0.000000e+00;
STAT76.STAT117 := 8.500000e-01;
STAT76.STAT118 := 0.000000e+00;
STAT76.STAT119 := 0.000000e+00;
STAT76.STAT120 := 0.000000e+00;
STAT76.STAT121 := 0.000000e+00;
STAT76.STAT122 := 0;
STAT76.STAT123 := 0.000000e+00;
STAT76.STAT124 := 0.000000e+00;
STAT76.STAT125 := 0.000000e+00;
STAT76.STAT126 := 0.000000e+00;
STAT127[1] := 0;
STAT127[2] := 0;
STAT127[3] := 0;
STAT127[4] := 0;
STAT127[5] := 0;
STAT128 := '';
STAT129 := 0;
STAT130[1] := 0;
STAT130[2] := 0;
STAT130[3] := 0;
STAT130[4] := 0;
STAT130[5] := 0;
STAT130[6] := 0;
STAT130[7] := 0;
STAT130[8] := 0;
STAT130[9] := 0;
STAT130[10] := 0;
STAT130[11] := 0;
STAT130[12] := 0;
STAT130[13] := 0;
STAT130[14] := 0;
STAT130[15] := 0;
STAT130[16] := 0;
STAT130[17] := 0;
STAT130[18] := 0;
STAT131.STAT132 := 0.000000e+00;
STAT131.STAT133 := 0.000000e+00;
STAT131.STAT134 := 1.000000e-03;
STAT131.STAT135 := 7.800000e-03;
STAT131.STAT136 := 1.390000e-02;
STAT131.STAT137 := 5.700000e+00;
STAT131.STAT138 := 2.000000e+00;
STAT131.STAT139 := 2.200000e+00;
STAT131.STAT140 := 2.100000e+01;
STAT131.STAT141 := 2.000000e+01;
STAT131.STAT142 := 5.000000e+00;
STAT131.STAT143 := 6.000000e+01;
STAT131.STAT144 := 5.000000e+01;
STAT131.STAT145 := 2.500000e+01;
STAT131.STAT146 := 4.000000e+01;
STAT131.STAT147 := 2.400000e+01;
STAT131.STAT148 := 1.400000e+01;
STAT131.STAT149 := 3.000000e-01;
STAT131.STAT150 := 3.000000e+01;
STAT131.STAT151 := 1.000000e+00;
STAT131.STAT152 := 4.000000e+00;
STAT131.STAT153 := 2.000000e+00;
STAT131.STAT154 := 1.000000e+02;
STAT131.STAT155 := 5.000000e+02;
STAT131.STAT156 := 5.000000e+01;
STAT131.STAT157 := 8.000000e+00;
STAT131.STAT158 := 1.900000e+01;
STAT131.STAT159 := 1;
STAT131.STAT160 := 2.000000e+02;
STAT131.STAT161 := 5.000000e-01;
STAT131.STAT162 := 4.500000e+02;
STAT131.STAT163 := 2.500000e+03;
STAT131.STAT164 := 1.220000e+01;
STAT131.STAT165 := 1.000000e+00;
STAT131.STAT166 := 3.950000e+02;
STAT131.STAT167 := -2.500000e+01;
STAT131.STAT168 := 3.618000e+01;
STAT131.STAT169 := 1.400000e+03;
STAT131.STAT170 := 2.520000e+03;
STAT131.STAT171 := 91;
STAT131.STAT172 := 1.000000e+02;
STAT131.STAT173 := 1.600000e+02;
STAT131.STAT174 := 3.200000e+00;
STAT131.STAT175 := 1.050000e+03;
STAT131.STAT176 := 4.600000e+01;
STAT131.STAT177 := 1.625000e+03;
STAT131.STAT178 := 1.000000e+00;
STAT131.STAT179 := 1.300000e+00;
STAT131.STAT180 := 4.090000e-02;
STAT131.STAT181 := 1.400000e-03;
STAT131.STAT182 := 4.500000e+02;
STAT131.STAT183 := W#16#0;
STAT131.STAT184 := W#16#78;
STAT131.STAT185 := W#16#1;
STAT131.STAT186 := 3.000000e+01;
STAT131.STAT187 := 4.000000e+01;
STAT131.STAT188 := 3.000000e+01;
STAT131.STAT189 := 5.000000e+00;
STAT131.STAT190 := 4.900000e-01;
STAT131.STAT191 := 3.000000e-01;
STAT131.STAT192 := 9.000000e-01;
STAT131.STAT193 := 1.500000e+01;
STAT131.STAT194 := 3.500000e+01;
STAT131.STAT195 := 5.000000e+01;
STAT131.STAT196 := 4.000000e+00;
STAT131.STAT197 := 2.000000e+01;
STAT131.STAT198 := 5.000000e+00;
STAT131.STAT199 := 5.000000e+00;
STAT131.STAT200 := 5.000000e+00;
STAT131.STAT201 := 5.000000e+00;
STAT131.STAT202 := 6.000000e+01;
STAT131.STAT203 := 0.000000e+00;
STAT131.STAT204 := 1.500000e+02;
STAT131.STAT205 := 1.650000e+02;
STAT131.STAT206 := 2.600000e+02;
STAT131.STAT207 := 1.650000e+02;
STAT131.STAT208 := 6.700000e+01;
STAT131.STAT209 := 300;
STAT131.STAT210 := 9.000000e+01;
STAT131.STAT211 := 8.700000e+01;
STAT131.STAT212 := 5.070000e+02;
STAT131.STAT213 := 2.110000e+02;
STAT131.STAT214 := 8.600000e+01;
STAT131.STAT215 := 8.500000e+01;
STAT131.STAT216 := 1.150000e+02;
STAT131.STAT217 := 3.200000e+01;
STAT131.STAT218 := 5.000000e+00;
STAT131.STAT219 := 5.000000e+00;
STAT131.STAT220 := 0.000000e+00;
STAT131.STAT221 := 0.000000e+00;
STAT131.STAT222 := 0.000000e+00;
STAT131.STAT223 := 0.000000e+00;
STAT131.STAT224 := 2.000000e+01;
STAT131.STAT225 := 5.000000e+00;
STAT131.STAT226 := 1.000000e+01;
STAT131.STAT227 := 5.000000e+01;
STAT131.STAT228 := 5.000000e+01;
STAT131.STAT229 := L#1500;
STAT131.STAT230 := L#1500;
STAT131.STAT231 := L#1000;
STAT131.STAT232 := L#1000;
STAT131.STAT233 := 30;
STAT131.STAT234 := 30;
STAT131.STAT235 := 10;
STAT131.STAT236 := 10;
STAT131.STAT237 := 10;
STAT131.STAT238 := 3.500000e+02;
STAT131.STAT239 := 30;
STAT131.STAT240 := 30;
STAT131.STAT241 := 30;
STAT131.STAT242 := 30;
STAT131.STAT243 := 30;
STAT131.STAT244 := 30;
STAT131.STAT245 := 30;
STAT131.STAT246 := 30;
STAT131.STAT247 := 3.000000e+01;
STAT131.STAT248 := 3.000000e+01;
STAT131.STAT249 := 0.000000e+00;
STAT131.STAT250 := 0.000000e+00;
STAT131.STAT251 := 0.000000e+00;
STAT131.STAT252 := 5.000000e+01;
STAT253 := FALSE;
STAT254 := 0.000000e+00;
END_DATA_BLOCK

View File

@ -1,15 +1,15 @@
# --- x3.py (Modificaciones v_final_2) ---
import re import re
import json import json
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import List, Dict, Optional, Union, Tuple, Any from typing import List, Dict, Optional, Union, Tuple, Any
import copy import copy
# --- Estructuras de Datos --- # --- Estructuras de Datos (sin cambios respecto a v_final que te di antes, incluyendo DbInfo con ambas listas/dicts para BEGIN) ---
@dataclass @dataclass
class ArrayDimension: class ArrayDimension:
lower_bound: int lower_bound: int
upper_bound: int upper_bound: int
@property @property
def count(self) -> int: def count(self) -> int:
return self.upper_bound - self.lower_bound + 1 return self.upper_bound - self.lower_bound + 1
@ -17,24 +17,23 @@ class ArrayDimension:
@dataclass @dataclass
class VariableInfo: class VariableInfo:
name: str name: str
data_type: str # Tipo base limpio (ej. "INT", "REAL", nombre del UDT sin comillas) data_type: str
byte_offset: float byte_offset: float
size_in_bytes: int # Para BOOL arrays, bytes que ocupa. Para BOOL individual, 0. size_in_bytes: int
bit_size: int = 0 # Para BOOL, 1. Para otros, 0. bit_size: int = 0
udt_source_name: Optional[str] = None # Nombre original del UDT con comillas, si es UDT udt_source_name: Optional[str] = None
string_length: Optional[int] = None string_length: Optional[int] = None
array_dimensions: List[ArrayDimension] = field(default_factory=list) array_dimensions: List[ArrayDimension] = field(default_factory=list)
initial_value: Optional[str] = None # Valor de la declaración initial_value: Optional[str] = None
current_value: Optional[str] = None # Valor efectivo (del bloque BEGIN o fallback a initial_value) current_value: Optional[str] = None
comment: Optional[str] = None comment: Optional[str] = None
children: List['VariableInfo'] = field(default_factory=list) # Para STRUCTs o UDTs expandidos children: List['VariableInfo'] = field(default_factory=list)
is_udt_expanded_member: bool = False is_udt_expanded_member: bool = False
# Nuevo campo para almacenar valores de elementos de array del bloque BEGIN current_element_values: Optional[Dict[str, str]] = None
current_element_values: Optional[Dict[str, str]] = None # Ej: {"1": "val1", "1,0":"val_multi"}
@dataclass @dataclass
class UdtInfo: class UdtInfo:
name: str # Nombre del UDT (sin comillas) name: str
family: Optional[str] = None family: Optional[str] = None
version: Optional[str] = None version: Optional[str] = None
members: List[VariableInfo] = field(default_factory=list) members: List[VariableInfo] = field(default_factory=list)
@ -42,14 +41,14 @@ class UdtInfo:
@dataclass @dataclass
class DbInfo: class DbInfo:
name: str # Nombre del DB (sin comillas) name: str
title: Optional[str] = None title: Optional[str] = None
family: Optional[str] = None family: Optional[str] = None
version: Optional[str] = None version: Optional[str] = None
members: List[VariableInfo] = field(default_factory=list) members: List[VariableInfo] = field(default_factory=list)
total_size_in_bytes: int = 0 total_size_in_bytes: int = 0
# Este diccionario almacena las asignaciones literales del bloque BEGIN _begin_block_assignments_ordered: List[Tuple[str, str]] = field(default_factory=list)
_initial_values_from_begin_block: Dict[str, str] = field(default_factory=dict) _initial_values_from_begin_block: Dict[str, str] = field(default_factory=dict) # Para búsquedas rápidas en _apply_current_values
@dataclass @dataclass
class ParsedData: class ParsedData:
@ -57,32 +56,24 @@ class ParsedData:
dbs: List[DbInfo] = field(default_factory=list) dbs: List[DbInfo] = field(default_factory=list)
@dataclass @dataclass
class OffsetContext: class OffsetContext: # Sin cambios
byte_offset: int = 0 byte_offset: int = 0
bit_offset: int = 0 # 0-7 bit_offset: int = 0
def get_combined_offset(self) -> float: def get_combined_offset(self) -> float:
if self.bit_offset == 0: if self.bit_offset == 0: return float(self.byte_offset)
return float(self.byte_offset)
return float(self.byte_offset * 10 + self.bit_offset) / 10.0 return float(self.byte_offset * 10 + self.bit_offset) / 10.0
def advance_bits(self, num_bits: int): def advance_bits(self, num_bits: int):
self.bit_offset += num_bits self.bit_offset += num_bits
self.byte_offset += self.bit_offset // 8 self.byte_offset += self.bit_offset // 8
self.bit_offset %= 8 self.bit_offset %= 8
def align_to_byte(self): def align_to_byte(self):
if self.bit_offset > 0: if self.bit_offset > 0: self.byte_offset += 1; self.bit_offset = 0
self.byte_offset += 1
self.bit_offset = 0
def align_to_word(self): def align_to_word(self):
self.align_to_byte() self.align_to_byte()
if self.byte_offset % 2 != 0: if self.byte_offset % 2 != 0: self.byte_offset += 1
self.byte_offset += 1
# --- Fin Estructuras de Datos --- # --- Fin Estructuras de Datos ---
S7_PRIMITIVE_SIZES = { S7_PRIMITIVE_SIZES = { # Sin cambios
"BOOL": (0, 1, True), "BYTE": (1, 1, False), "CHAR": (1, 1, False), "BOOL": (0, 1, True), "BYTE": (1, 1, False), "CHAR": (1, 1, False),
"SINT": (1, 1, False), "USINT": (1, 1, False), "WORD": (2, 2, False), "SINT": (1, 1, False), "USINT": (1, 1, False), "WORD": (2, 2, False),
"INT": (2, 2, False), "UINT": (2, 2, False), "S5TIME": (2, 2, False), "INT": (2, 2, False), "UINT": (2, 2, False), "S5TIME": (2, 2, False),
@ -94,18 +85,18 @@ S7_PRIMITIVE_SIZES = {
} }
class S7Parser: class S7Parser:
def __init__(self): def __init__(self): # Sin cambios en regex básicos
self.parsed_data = ParsedData() self.parsed_data = ParsedData()
self.known_udts: Dict[str, UdtInfo] = {} # Clave es el nombre del UDT sin comillas self.known_udts: Dict[str, UdtInfo] = {}
self.type_start_regex = re.compile(r'^\s*TYPE\s+"([^"]+)"', re.IGNORECASE) self.type_start_regex = re.compile(r'^\s*TYPE\s+"([^"]+)"', re.IGNORECASE)
self.db_start_regex = re.compile(r'^\s*DATA_BLOCK\s+"([^"]+)"', re.IGNORECASE) self.db_start_regex = re.compile(r'^\s*DATA_BLOCK\s+"([^"]+)"', re.IGNORECASE)
self.property_regex = re.compile(r'^\s*([A-Z_]+)\s*:\s*(.+?)(?:\s*;)?\s*(?://.*)?$', re.IGNORECASE) # Property regex: el valor NO debe terminar obligatoriamente en ; y puede ser capturado de forma no greedy
self.property_regex = re.compile(r'^\s*([A-Z_]+)\s*:\s*(.+?)\s*(?://.*)?$', re.IGNORECASE)
self.struct_start_regex = re.compile(r'^\s*STRUCT\b', re.IGNORECASE) self.struct_start_regex = re.compile(r'^\s*STRUCT\b', re.IGNORECASE)
self.end_struct_regex = re.compile(r'^\s*END_STRUCT\b', re.IGNORECASE) self.end_struct_regex = re.compile(r'^\s*END_STRUCT\b', re.IGNORECASE)
self.end_type_regex = re.compile(r'^\s*END_TYPE\b', re.IGNORECASE) self.end_type_regex = re.compile(r'^\s*END_TYPE\b', re.IGNORECASE)
self.end_db_regex = re.compile(r'^\s*END_DATA_BLOCK\b', re.IGNORECASE) self.end_db_regex = re.compile(r'^\s*END_DATA_BLOCK\b', re.IGNORECASE)
self.begin_regex = re.compile(r'^\s*BEGIN\b', re.IGNORECASE) self.begin_regex = re.compile(r'^\s*BEGIN\b', re.IGNORECASE)
self.var_regex_simplified = re.compile( self.var_regex_simplified = re.compile(
r'^\s*(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*' r'^\s*(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*'
r'(?P<typefull>' r'(?P<typefull>'
@ -118,22 +109,14 @@ class S7Parser:
re.IGNORECASE re.IGNORECASE
) )
self.array_dim_regex = re.compile(r'(\d+)\s*\.\.\s*(\d+)') self.array_dim_regex = re.compile(r'(\d+)\s*\.\.\s*(\d+)')
# Regex para capturar elementos de array en el bloque BEGIN, ej: MyArray[1] o MyArray[1,2]
self.array_element_assign_regex_template = r'^\s*{array_var_name_escaped}\[(?P<indices>[0-9,\s]+)\]\s*$'
# _get_type_details, _adjust_children_offsets, _parse_struct_members (sin cambios respecto a v_final)
def _get_type_details(self, type_name_raw_cleaned: str) -> Tuple[int, int, bool, str]: def _get_type_details(self, type_name_raw_cleaned: str) -> Tuple[int, int, bool, str]:
"""
type_name_raw_cleaned: Nombre del tipo ya sin comillas y en mayúsculas para primitivos,
o en su caso original para UDTs.
Returns: (size_in_bytes, alignment_req_bytes, is_bool, effective_type_name_for_lookup)
"""
type_name_upper = type_name_raw_cleaned.upper() type_name_upper = type_name_raw_cleaned.upper()
if type_name_upper in S7_PRIMITIVE_SIZES: if type_name_upper in S7_PRIMITIVE_SIZES:
size, align, is_bool = S7_PRIMITIVE_SIZES[type_name_upper] size, align, is_bool = S7_PRIMITIVE_SIZES[type_name_upper]
return size, align, is_bool, type_name_upper return size, align, is_bool, type_name_upper
elif type_name_raw_cleaned in self.known_udts: # Búsqueda case-sensitive para UDTs elif type_name_raw_cleaned in self.known_udts:
udt = self.known_udts[type_name_raw_cleaned] udt = self.known_udts[type_name_raw_cleaned]
return udt.total_size_in_bytes, 2, False, type_name_raw_cleaned return udt.total_size_in_bytes, 2, False, type_name_raw_cleaned
elif type_name_upper == "STRUCT": elif type_name_upper == "STRUCT":
@ -144,39 +127,32 @@ class S7Parser:
def _adjust_children_offsets(children: List[VariableInfo], base_offset_add: float): def _adjust_children_offsets(children: List[VariableInfo], base_offset_add: float):
for child in children: for child in children:
child.byte_offset += base_offset_add child.byte_offset += base_offset_add
if child.byte_offset == float(int(child.byte_offset)): # Limpiar .0 innecesario if child.byte_offset == float(int(child.byte_offset)):
child.byte_offset = float(int(child.byte_offset)) child.byte_offset = float(int(child.byte_offset))
if child.children: if child.children:
S7Parser._adjust_children_offsets(child.children, base_offset_add) S7Parser._adjust_children_offsets(child.children, base_offset_add)
def _parse_struct_members(self, lines: List[str], current_line_idx: int, def _parse_struct_members(self, lines: List[str], current_line_idx: int,
parent_members_list: List[VariableInfo], parent_members_list: List[VariableInfo],
active_context: OffsetContext, active_context: OffsetContext,
is_top_level_struct_in_block: bool = False) -> int: is_top_level_struct_in_block: bool = False) -> int:
idx_to_process = current_line_idx idx_to_process = current_line_idx
while idx_to_process < len(lines): while idx_to_process < len(lines):
original_line_text = lines[idx_to_process].strip() original_line_text = lines[idx_to_process].strip()
line_to_parse = original_line_text line_to_parse = original_line_text
line_comment = None line_comment = None
comment_marker_idx = original_line_text.find("//") comment_marker_idx = original_line_text.find("//")
if comment_marker_idx != -1: if comment_marker_idx != -1:
line_to_parse = original_line_text[:comment_marker_idx].strip() line_to_parse = original_line_text[:comment_marker_idx].strip()
line_comment = original_line_text[comment_marker_idx + 2:].strip() line_comment = original_line_text[comment_marker_idx + 2:].strip()
line_index_for_return = idx_to_process line_index_for_return = idx_to_process
idx_to_process += 1 idx_to_process += 1
if not line_to_parse: continue if not line_to_parse: continue
if self.end_struct_regex.match(line_to_parse): if self.end_struct_regex.match(line_to_parse):
if not is_top_level_struct_in_block: if not is_top_level_struct_in_block:
active_context.align_to_byte() active_context.align_to_byte()
if active_context.byte_offset % 2 != 0: active_context.byte_offset += 1 if active_context.byte_offset % 2 != 0: active_context.byte_offset += 1
return idx_to_process return idx_to_process
if is_top_level_struct_in_block and \ if is_top_level_struct_in_block and \
(self.end_type_regex.match(line_to_parse) or \ (self.end_type_regex.match(line_to_parse) or \
self.end_db_regex.match(line_to_parse) or \ self.end_db_regex.match(line_to_parse) or \
@ -184,78 +160,57 @@ class S7Parser:
active_context.align_to_byte() active_context.align_to_byte()
if active_context.byte_offset % 2 != 0: active_context.byte_offset += 1 if active_context.byte_offset % 2 != 0: active_context.byte_offset += 1
return line_index_for_return return line_index_for_return
var_match = self.var_regex_simplified.match(line_to_parse) var_match = self.var_regex_simplified.match(line_to_parse)
if var_match: if var_match:
var_data = var_match.groupdict() var_data = var_match.groupdict()
# data_type se refiere al tipo base limpio, udt_source_name al original con comillas
raw_base_type_from_regex = var_data['basetype'].strip() raw_base_type_from_regex = var_data['basetype'].strip()
clean_data_type = raw_base_type_from_regex.strip('"') clean_data_type = raw_base_type_from_regex.strip('"')
udt_source_name_val = raw_base_type_from_regex if raw_base_type_from_regex.startswith('"') else None udt_source_name_val = raw_base_type_from_regex if raw_base_type_from_regex.startswith('"') else None
var_info = VariableInfo(name=var_data['name'], var_info = VariableInfo(name=var_data['name'],
data_type=clean_data_type, data_type=clean_data_type,
byte_offset=0, size_in_bytes=0, byte_offset=0, size_in_bytes=0,
udt_source_name=udt_source_name_val) udt_source_name=udt_source_name_val)
if var_data.get('initval'): var_info.initial_value = var_data['initval'].strip()
if var_data.get('initval'): if line_comment: var_info.comment = line_comment
var_info.initial_value = var_data['initval'].strip()
if line_comment:
var_info.comment = line_comment
num_array_elements = 1 num_array_elements = 1
if var_data['arraydims']: if var_data['arraydims']:
for dim_match in self.array_dim_regex.finditer(var_data['arraydims']): for dim_match in self.array_dim_regex.finditer(var_data['arraydims']):
var_info.array_dimensions.append(ArrayDimension(int(dim_match.group(1)), int(dim_match.group(2)))) var_info.array_dimensions.append(ArrayDimension(int(dim_match.group(1)), int(dim_match.group(2))))
if var_info.array_dimensions: if var_info.array_dimensions:
for dim in var_info.array_dimensions: num_array_elements *= dim.count for dim in var_info.array_dimensions: num_array_elements *= dim.count
if var_info.data_type.upper() == "STRUCT":
if var_info.data_type.upper() == "STRUCT": # Un miembro definido como STRUCT explícitamente
active_context.align_to_word() active_context.align_to_word()
var_info.byte_offset = active_context.get_combined_offset() var_info.byte_offset = active_context.get_combined_offset()
nested_struct_context = OffsetContext() nested_struct_context = OffsetContext()
idx_after_nested_struct = self._parse_struct_members( idx_after_nested_struct = self._parse_struct_members(
lines, idx_to_process, var_info.children, lines, idx_to_process, var_info.children,
nested_struct_context, is_top_level_struct_in_block=False nested_struct_context, is_top_level_struct_in_block=False
) )
var_info.size_in_bytes = nested_struct_context.byte_offset var_info.size_in_bytes = nested_struct_context.byte_offset
# Ajustar offsets de los hijos del struct anidado para que sean globales
for child in var_info.children: for child in var_info.children:
child.byte_offset += var_info.byte_offset child.byte_offset += var_info.byte_offset
if child.byte_offset == float(int(child.byte_offset)): if child.byte_offset == float(int(child.byte_offset)):
child.byte_offset = float(int(child.byte_offset)) child.byte_offset = float(int(child.byte_offset))
if child.children: if child.children: S7Parser._adjust_children_offsets(child.children, var_info.byte_offset)
S7Parser._adjust_children_offsets(child.children, var_info.byte_offset)
active_context.byte_offset += var_info.size_in_bytes active_context.byte_offset += var_info.size_in_bytes
idx_to_process = idx_after_nested_struct idx_to_process = idx_after_nested_struct
elif var_info.data_type.upper() == "STRING" and var_data['stringlength']: elif var_info.data_type.upper() == "STRING" and var_data['stringlength']:
var_info.string_length = int(var_data['stringlength']) var_info.string_length = int(var_data['stringlength'])
unit_size = var_info.string_length + 2 # N chars + 2 header bytes unit_size = var_info.string_length + 2
active_context.align_to_word() # STRING se alinea a palabra active_context.align_to_word()
var_info.byte_offset = active_context.get_combined_offset() var_info.byte_offset = active_context.get_combined_offset()
var_info.size_in_bytes = unit_size * num_array_elements var_info.size_in_bytes = unit_size * num_array_elements
active_context.byte_offset += var_info.size_in_bytes active_context.byte_offset += var_info.size_in_bytes
else:
else: # Primitivo o instancia de UDT
# Usar var_info.data_type (limpio) para _get_type_details
unit_size_bytes, unit_alignment_req, is_bool, type_name_for_udt_lookup = self._get_type_details(var_info.data_type) unit_size_bytes, unit_alignment_req, is_bool, type_name_for_udt_lookup = self._get_type_details(var_info.data_type)
if is_bool: if is_bool:
var_info.bit_size = 1 var_info.bit_size = 1
var_info.byte_offset = active_context.get_combined_offset() var_info.byte_offset = active_context.get_combined_offset()
active_context.advance_bits(num_array_elements) active_context.advance_bits(num_array_elements)
start_byte_abs = int(var_info.byte_offset) start_byte_abs = int(var_info.byte_offset)
start_bit_in_byte = int(round((var_info.byte_offset - start_byte_abs) * 10)) start_bit_in_byte = int(round((var_info.byte_offset - start_byte_abs) * 10))
if num_array_elements == 1: if num_array_elements == 1: var_info.size_in_bytes = 0
var_info.size_in_bytes = 0 # Convención para un solo bit else:
else: # Array de BOOLs
bits_rem = num_array_elements; bytes_spanned = 0 bits_rem = num_array_elements; bytes_spanned = 0
if start_bit_in_byte > 0: if start_bit_in_byte > 0:
bits_in_first = 8 - start_bit_in_byte bits_in_first = 8 - start_bit_in_byte
@ -263,115 +218,68 @@ class S7Parser:
else: bytes_spanned = 1; bits_rem -= bits_in_first; bytes_spanned += (bits_rem + 7) // 8 else: bytes_spanned = 1; bits_rem -= bits_in_first; bytes_spanned += (bits_rem + 7) // 8
else: bytes_spanned = (bits_rem + 7) // 8 else: bytes_spanned = (bits_rem + 7) // 8
var_info.size_in_bytes = bytes_spanned var_info.size_in_bytes = bytes_spanned
else:
else: # No es BOOL (Primitivo > byte, o UDT)
active_context.align_to_byte() active_context.align_to_byte()
if unit_alignment_req == 2: active_context.align_to_word() if unit_alignment_req == 2: active_context.align_to_word()
var_info.byte_offset = active_context.get_combined_offset() var_info.byte_offset = active_context.get_combined_offset()
var_info.size_in_bytes = unit_size_bytes * num_array_elements var_info.size_in_bytes = unit_size_bytes * num_array_elements
active_context.byte_offset += var_info.size_in_bytes active_context.byte_offset += var_info.size_in_bytes
if type_name_for_udt_lookup in self.known_udts and not is_bool:
if type_name_for_udt_lookup in self.known_udts and not is_bool: # Es una instancia de UDT
udt_def = self.known_udts[type_name_for_udt_lookup] udt_def = self.known_udts[type_name_for_udt_lookup]
udt_instance_abs_start_offset = var_info.byte_offset udt_instance_abs_start_offset = var_info.byte_offset
for udt_member_template in udt_def.members: for udt_member_template in udt_def.members:
expanded_member = copy.deepcopy(udt_member_template) expanded_member = copy.deepcopy(udt_member_template)
expanded_member.is_udt_expanded_member = True expanded_member.is_udt_expanded_member = True
expanded_member.byte_offset += udt_instance_abs_start_offset # Hacer absoluto expanded_member.byte_offset += udt_instance_abs_start_offset
if expanded_member.byte_offset == float(int(expanded_member.byte_offset)): if expanded_member.byte_offset == float(int(expanded_member.byte_offset)):
expanded_member.byte_offset = float(int(expanded_member.byte_offset)) expanded_member.byte_offset = float(int(expanded_member.byte_offset))
if expanded_member.children:
if expanded_member.children: # Si el miembro del UDT era un STRUCT
S7Parser._adjust_children_offsets(expanded_member.children, udt_instance_abs_start_offset) S7Parser._adjust_children_offsets(expanded_member.children, udt_instance_abs_start_offset)
var_info.children.append(expanded_member) var_info.children.append(expanded_member)
parent_members_list.append(var_info) parent_members_list.append(var_info)
else: # No es variable, ni fin de struct, ni fin de bloque principal else:
if line_to_parse and \ if line_to_parse and not self.struct_start_regex.match(line_to_parse):
not self.struct_start_regex.match(line_to_parse): # Si no es tampoco un "STRUCT" de inicio de miembro print(f"DEBUG (struct_members): Line not parsed: Original='{original_line_text}' | Processed='{line_to_parse}'")
print(f"DEBUG: Line not parsed as variable or known keyword: Original='{original_line_text}' | Processed='{line_to_parse}'")
# El padding final del struct/bloque se maneja al detectar END_STRUCT o END_TYPE/DB/BEGIN
return idx_to_process return idx_to_process
def _parse_begin_block(self, lines: List[str], start_idx: int, db_info: DbInfo) -> int: def _parse_begin_block(self, lines: List[str], start_idx: int, db_info: DbInfo) -> int:
idx = start_idx idx = start_idx
assignment_regex = re.compile(r'^\s*(?P<path>.+?)\s*:=\s*(?P<value>.+?)\s*;?\s*$', re.IGNORECASE) assignment_regex = re.compile(r'^\s*(?P<path>.+?)\s*:=\s*(?P<value>.+?)\s*;?\s*$', re.IGNORECASE)
while idx < len(lines): while idx < len(lines):
original_line = lines[idx].strip() original_line = lines[idx].strip()
line_to_parse = original_line line_to_parse = original_line
comment_marker = original_line.find("//") comment_marker = original_line.find("//")
if comment_marker != -1: if comment_marker != -1: line_to_parse = original_line[:comment_marker].strip()
line_to_parse = original_line[:comment_marker].strip() if self.end_db_regex.match(line_to_parse): return idx
# Comentarios en líneas de asignación no se guardan estructuradamente por ahora
if self.end_db_regex.match(line_to_parse):
return idx
idx += 1 idx += 1
if not line_to_parse: continue if not line_to_parse: continue
match = assignment_regex.match(line_to_parse) match = assignment_regex.match(line_to_parse)
if match: if match:
path = match.group("path").strip() path, value = match.group("path").strip(), match.group("value").strip().rstrip(';').strip()
value = match.group("value").strip().rstrip(';').strip() db_info._begin_block_assignments_ordered.append((path, value)) # Guardar ordenado
db_info._initial_values_from_begin_block[path] = value db_info._initial_values_from_begin_block[path] = value # Guardar para búsqueda
# else: # else: print(f"DEBUG (begin_block): Line not matched: '{original_line}'")
# print(f"DEBUG: Line in BEGIN not matched: '{original_line}'")
raise SyntaxError("Se esperaba END_DATA_BLOCK después de la sección BEGIN.") raise SyntaxError("Se esperaba END_DATA_BLOCK después de la sección BEGIN.")
def _apply_current_values(self, members: List[VariableInfo], begin_values: Dict[str, str], current_path_prefix: str = ""): def _apply_current_values(self, members: List[VariableInfo], begin_values: Dict[str, str], current_path_prefix: str = ""):
for var_info in members: for var_info in members:
full_member_path = f"{current_path_prefix}{var_info.name}" full_member_path = f"{current_path_prefix}{var_info.name}"
if var_info.array_dimensions: if var_info.array_dimensions:
var_info.current_element_values = {} var_info.current_element_values = {}
# Lógica para buscar elementos de array en begin_values prefix_for_search = full_member_path + "["
# Asumimos que las claves en begin_values son como "ArrayName[idx]" o "Struct.ArrayName[idx,idx2]"
# Construir un patrón para buscar elementos de este array específico
# Escapar el nombre del array por si contiene caracteres especiales de regex
# Y luego añadir el patrón para los corchetes e índices.
# Esto es una simplificación. Un parseo robusto de índices multidimensionales es más complejo.
# Ejemplo de clave en begin_values: "Spare1[1]", "Path.To.Array[5]"
prefix_for_search = full_member_path + "[" # ej. "Spare1["
for key_in_begin, val_in_begin in begin_values.items(): for key_in_begin, val_in_begin in begin_values.items():
if key_in_begin.startswith(prefix_for_search) and key_in_begin.endswith("]"): if key_in_begin.startswith(prefix_for_search) and key_in_begin.endswith("]"):
# Extraer el contenido de los corchetes
try: try:
indices_str = key_in_begin[len(prefix_for_search):-1] indices_str = key_in_begin[len(prefix_for_search):-1]
var_info.current_element_values[indices_str] = val_in_begin var_info.current_element_values[indices_str] = val_in_begin
except: except: print(f"Advertencia: No se pudo parsear el índice para: {key_in_begin}")
print(f"Advertencia: No se pudo parsear el índice para la clave del array: {key_in_begin}") if not var_info.current_element_values: var_info.current_element_values = None
if full_member_path in begin_values: var_info.current_value = begin_values[full_member_path]
if not var_info.current_element_values: elif full_member_path in begin_values: var_info.current_value = begin_values[full_member_path]
var_info.current_element_values = None # No guardar dict vacío elif var_info.initial_value is not None: var_info.current_value = var_info.initial_value
if var_info.children and not var_info.is_udt_expanded_member:
# El current_value del array en sí mismo no se establece a menos que haya una asignación global
# como "ArrayName := ..." lo cual es raro para arrays complejos en BEGIN.
if full_member_path in begin_values: # Asignación global al array?
var_info.current_value = begin_values[full_member_path]
elif full_member_path in begin_values: # Variable simple
var_info.current_value = begin_values[full_member_path]
elif var_info.initial_value is not None: # Fallback a valor de declaración
var_info.current_value = var_info.initial_value
# Aplicar recursivamente para hijos de STRUCTs (no UDTs expandidos directamente aquí)
if var_info.children and not var_info.is_udt_expanded_member: # Es un STRUCT definido aquí
self._apply_current_values(var_info.children, begin_values, f"{full_member_path}.") self._apply_current_values(var_info.children, begin_values, f"{full_member_path}.")
# Para miembros expandidos de UDT (is_udt_expanded_member = True), elif var_info.udt_source_name and var_info.children: # Instancia UDT con miembros expandidos
# sus current_values se establecen si su ruta completa (ej. "MyUdtInstance._Member") está en begin_values.
# Esto se maneja en la iteración principal si los hijos UDT son procesados.
# La llamada recursiva anterior para STRUCTs anidados maneja "MyStruct.MyUdtInstance._Member".
# Si var_info es una instancia de UDT (tiene udt_source_name y children son sus miembros expandidos)
elif var_info.udt_source_name and var_info.children:
self._apply_current_values(var_info.children, begin_values, f"{full_member_path}.") self._apply_current_values(var_info.children, begin_values, f"{full_member_path}.")
@ -383,117 +291,123 @@ class S7Parser:
current_block_handler: Optional[Union[UdtInfo, DbInfo]] = None current_block_handler: Optional[Union[UdtInfo, DbInfo]] = None
active_block_context = OffsetContext() active_block_context = OffsetContext()
parsing_title_value_next_line = False # Estado para parsear valor de TITLE
idx = 0 idx = 0
while idx < len(lines): while idx < len(lines):
original_line_with_space = lines[idx] original_line_text = lines[idx] # Mantener espacios iniciales para manejo de TITLE
original_line = original_line_with_space.strip() stripped_original_line = original_line_text.strip()
line_to_parse = original_line line_to_parse = stripped_original_line
comment_marker = original_line.find("//") # line_comment_content = None # No es necesario aquí ya que property_regex lo ignora
comment_marker = stripped_original_line.find("//")
if comment_marker != -1: if comment_marker != -1:
line_to_parse = original_line[:comment_marker].strip() line_to_parse = stripped_original_line[:comment_marker].strip()
if parsing_title_value_next_line and isinstance(current_block_handler, DbInfo):
# El valor de TITLE está indentado y es la línea actual completa (con llaves)
title_value_candidate = original_line_text.strip() # Usar la línea original strip()
if title_value_candidate.startswith("{") and title_value_candidate.endswith("}"):
current_block_handler.title = title_value_candidate
print(f"DEBUG: Parsed TITLE value: {current_block_handler.title}")
else:
print(f"Advertencia: Se esperaba valor de TITLE {{...}} pero se encontró: '{title_value_candidate}' en la línea '{original_line_text.strip()}'")
parsing_title_value_next_line = False # Resetear estado, ya sea que se haya encontrado o no
idx += 1; continue # Consumir esta línea y pasar a la siguiente
type_match = self.type_start_regex.match(line_to_parse) type_match = self.type_start_regex.match(line_to_parse)
db_match = self.db_start_regex.match(line_to_parse) db_match = self.db_start_regex.match(line_to_parse)
if type_match: if type_match:
udt_name = type_match.group(1) udt_name = type_match.group(1); current_block_handler = UdtInfo(name=udt_name)
current_block_handler = UdtInfo(name=udt_name) self.parsed_data.udts.append(current_block_handler); active_block_context = OffsetContext()
self.parsed_data.udts.append(current_block_handler)
active_block_context = OffsetContext()
idx +=1; continue idx +=1; continue
elif db_match: elif db_match:
db_name = db_match.group(1) db_name = db_match.group(1); current_block_handler = DbInfo(name=db_name)
current_block_handler = DbInfo(name=db_name) self.parsed_data.dbs.append(current_block_handler); active_block_context = OffsetContext()
self.parsed_data.dbs.append(current_block_handler)
active_block_context = OffsetContext()
idx +=1; continue idx +=1; continue
if not current_block_handler: if not current_block_handler: idx +=1; continue
idx +=1; continue
prop_match = self.property_regex.match(original_line) # Las propiedades pueden tener comentarios # Manejo especial para "TITLE ="
if line_to_parse.upper() == "TITLE =":
if isinstance(current_block_handler, DbInfo):
parsing_title_value_next_line = True
print(f"DEBUG: Found 'TITLE =', expecting value on next line.")
idx += 1; continue
prop_match = self.property_regex.match(stripped_original_line) # Usar stripped_original_line para que la regex vea la línea como en el archivo
struct_keyword_match = self.struct_start_regex.match(line_to_parse) struct_keyword_match = self.struct_start_regex.match(line_to_parse)
if prop_match: if prop_match and not parsing_title_value_next_line:
key, value = prop_match.group(1).upper(), prop_match.group(2).strip() key, value = prop_match.group(1).upper(), prop_match.group(2).strip()
# El punto y coma de las propiedades es opcional en la regex y se quita si está
if value.endswith(';'): value = value[:-1].strip()
attr = key.lower() attr = key.lower()
if hasattr(current_block_handler, attr): setattr(current_block_handler, attr, value) if hasattr(current_block_handler, attr):
if attr == 'title' and current_block_handler.title is not None: pass
else: setattr(current_block_handler, attr, value)
# else: print(f"DEBUG: Property '{key}' not directly settable on {type(current_block_handler)}")
elif struct_keyword_match and not current_block_handler.members: # Inicio del STRUCT principal del bloque elif struct_keyword_match and not current_block_handler.members:
idx = self._parse_struct_members(lines, idx + 1, current_block_handler.members, idx = self._parse_struct_members(lines, idx + 1, current_block_handler.members,
active_block_context, is_top_level_struct_in_block=True) active_block_context, is_top_level_struct_in_block=True)
continue continue
elif self.begin_regex.match(line_to_parse) and isinstance(current_block_handler, DbInfo): elif self.begin_regex.match(line_to_parse) and isinstance(current_block_handler, DbInfo):
# El tamaño total de la sección de declaración se finaliza aquí
current_block_handler.total_size_in_bytes = active_block_context.byte_offset current_block_handler.total_size_in_bytes = active_block_context.byte_offset
idx = self._parse_begin_block(lines, idx + 1, current_block_handler) idx = self._parse_begin_block(lines, idx + 1, current_block_handler)
continue continue
elif self.end_type_regex.match(line_to_parse) and isinstance(current_block_handler, UdtInfo): elif self.end_type_regex.match(line_to_parse) and isinstance(current_block_handler, UdtInfo):
# Si total_size_in_bytes no fue establecido (ej. UDT vacío o error), calcularlo aquí if current_block_handler.total_size_in_bytes == 0: current_block_handler.total_size_in_bytes = active_block_context.byte_offset
if current_block_handler.total_size_in_bytes == 0:
current_block_handler.total_size_in_bytes = active_block_context.byte_offset
self.known_udts[current_block_handler.name] = current_block_handler self.known_udts[current_block_handler.name] = current_block_handler
print(f"Parsed UDT: {current_block_handler.name}, Size: {current_block_handler.total_size_in_bytes} bytes. Members: {len(current_block_handler.members)}") print(f"Parsed UDT: {current_block_handler.name}, Size: {current_block_handler.total_size_in_bytes}b, Members: {len(current_block_handler.members)}")
current_block_handler = None current_block_handler = None; parsing_title_value_next_line = False
elif self.end_db_regex.match(line_to_parse) and isinstance(current_block_handler, DbInfo): elif self.end_db_regex.match(line_to_parse) and isinstance(current_block_handler, DbInfo):
if current_block_handler.total_size_in_bytes == 0 : # Si no hubo sección BEGIN if current_block_handler.total_size_in_bytes == 0 : current_block_handler.total_size_in_bytes = active_block_context.byte_offset
current_block_handler.total_size_in_bytes = active_block_context.byte_offset
# Aplicar valores del bloque BEGIN a los current_value de los miembros
self._apply_current_values(current_block_handler.members, current_block_handler._initial_values_from_begin_block) self._apply_current_values(current_block_handler.members, current_block_handler._initial_values_from_begin_block)
print(f"Parsed DB: {current_block_handler.name}, Decl. Size: {current_block_handler.total_size_in_bytes} bytes. Members: {len(current_block_handler.members)}") print(f"Parsed DB: {current_block_handler.name}, Decl.Size: {current_block_handler.total_size_in_bytes}b, Members: {len(current_block_handler.members)}, BEGIN assigns: {len(current_block_handler._begin_block_assignments_ordered)}")
current_block_handler = None current_block_handler = None; parsing_title_value_next_line = False
# else:
# if line_to_parse: # Si no está vacía y no fue ninguna de las anteriores
# print(f"DEBUG (main_loop): Line not processed: '{stripped_original_line}' | Parsed as: '{line_to_parse}'")
idx += 1 idx += 1
return self.parsed_data return self.parsed_data
# --- Serializador JSON Personalizado --- # --- Serializador JSON Personalizado en x3.py ---
def custom_json_serializer(obj: Any) -> Any: def custom_json_serializer(obj: Any) -> Any:
if isinstance(obj, OffsetContext): return None # No serializar OffsetContext if isinstance(obj, OffsetContext): return None
if hasattr(obj, '__dict__'): if hasattr(obj, '__dict__'):
# Incluir _initial_values_from_begin_block y _begin_block_assignments_ordered
# Filtrar solo None y listas vacías, no por nombre de campo específico a menos que sea temporal
d = {k: v for k, v in obj.__dict__.items() d = {k: v for k, v in obj.__dict__.items()
if v is not None and \ if not (v is None or (isinstance(v, list) and not v))}
not (isinstance(v, list) and not v)} # Ya no filtra _initial_values_from_begin_block
# Asegurar que los booleanos y diccionarios de elementos de array se manejen bien
if isinstance(obj, VariableInfo): if isinstance(obj, VariableInfo):
# Asegurar que 'is_udt_expanded_member' esté presente si es False if not obj.is_udt_expanded_member and 'is_udt_expanded_member' not in d : # Añadir si es False y no está
if 'is_udt_expanded_member' not in d and obj.is_udt_expanded_member is False:
d['is_udt_expanded_member'] = False d['is_udt_expanded_member'] = False
elif obj.is_udt_expanded_member is True: # Asegurar que se incluya si es True if not obj.current_element_values and 'current_element_values' in d: # Quitar si es un dict vacío
d['is_udt_expanded_member'] = True
# Incluir current_element_values si existe y no está vacío
if hasattr(obj, 'current_element_values') and obj.current_element_values:
d['current_element_values'] = obj.current_element_values
# Eliminarlo si está presente pero vacío (ya que el default es None)
elif hasattr(obj, 'current_element_values') and 'current_element_values' in d and not d['current_element_values']:
del d['current_element_values'] del d['current_element_values']
if isinstance(obj, DbInfo):
if not obj._begin_block_assignments_ordered and '_begin_block_assignments_ordered' in d:
del d['_begin_block_assignments_ordered']
if not obj._initial_values_from_begin_block and '_initial_values_from_begin_block' in d:
del d['_initial_values_from_begin_block']
return d return d
raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable") raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable")
# --- Bloque Principal --- # --- Bloque Principal ---
if __name__ == "__main__": if __name__ == "__main__":
parser = S7Parser() parser = S7Parser()
# Asegúrate que este path es el correcto para tu archivo .db o .db.txt filepath = "db1001_data.db.txt"
filepath = "db1001_format.db.txt"
print(f"Intentando parsear el archivo: {filepath}") print(f"Intentando parsear el archivo: {filepath}")
parsed_result = parser.parse_file(filepath) parsed_result = parser.parse_file(filepath)
json_output_filename = "parsed_s7_data_stat.json"
# Nuevo nombre para el archivo JSON de salida para esta versión
json_output_filename = "parsed_s7_data.json"
print(f"\nParseo completo. Intentando serializar a JSON.") print(f"\nParseo completo. Intentando serializar a JSON.")
try: try:
json_output = json.dumps(parsed_result, default=custom_json_serializer, indent=2) json_output = json.dumps(parsed_result, default=custom_json_serializer, indent=2)
# print(json_output) # Descomentar para ver el JSON en la consola with open(json_output_filename, "w", encoding='utf-8') as f: f.write(json_output)
with open(json_output_filename, "w", encoding='utf-8') as f:
f.write(json_output)
print(f"Resultado guardado en: {json_output_filename}") print(f"Resultado guardado en: {json_output_filename}")
except Exception as e: except Exception as e: print(f"Error durante la serialización JSON o escritura de archivo: {e}")
print(f"Error durante la serialización JSON o escritura de archivo: {e}")

View File

@ -1,287 +1,174 @@
# --- x4.py (Modificaciones v_final_2) ---
import json import json
from typing import List, Dict, Any, Union from typing import List, Dict, Any
# format_data_type_for_source (sin cambios respecto a la v5 que te di antes)
def format_data_type_for_source(var_info: Dict[str, Any]) -> str: def format_data_type_for_source(var_info: Dict[str, Any]) -> str:
"""Formatea la declaración de tipo completa para la variable en S7 source."""
base_type = var_info.get("udt_source_name") if var_info.get("udt_source_name") else var_info["data_type"] base_type = var_info.get("udt_source_name") if var_info.get("udt_source_name") else var_info["data_type"]
type_str = "" type_str = ""
if var_info.get("array_dimensions"): if var_info.get("array_dimensions"):
dims_str = ",".join([f"{d['lower_bound']}..{d['upper_bound']}" for d in var_info["array_dimensions"]]) dims_str = ",".join([f"{d['lower_bound']}..{d['upper_bound']}" for d in var_info["array_dimensions"]])
type_str += f"ARRAY [{dims_str}] OF " type_str += f"ARRAY [{dims_str}] OF "
type_str += base_type type_str += base_type
if var_info["data_type"].upper() == "STRING" and var_info.get("string_length") is not None: if var_info["data_type"].upper() == "STRING" and var_info.get("string_length") is not None:
type_str += f"[{var_info['string_length']}]" type_str += f"[{var_info['string_length']}]"
return type_str return type_str
def generate_variable_declaration_for_source(var_info: Dict[str, Any], indent_level: int) -> str: def generate_variable_declaration_for_source(var_info: Dict[str, Any], indent_level: int) -> str:
"""Genera una línea de declaración de variable S7."""
indent_str = " " * indent_level indent_str = " " * indent_level
type_declaration_str = format_data_type_for_source(var_info) type_declaration_str = format_data_type_for_source(var_info)
line = f'{indent_str}{var_info["name"]} : {type_declaration_str}' line = f'{indent_str}{var_info["name"]} : {type_declaration_str}'
if var_info.get("initial_value") is not None: if var_info.get("initial_value") is not None:
initial_val = var_info["initial_value"] initial_val = var_info["initial_value"]
if isinstance(initial_val, bool): initial_val_str = "TRUE" if isinstance(initial_val, bool) and initial_val else \
initial_val_str = "TRUE" if initial_val else "FALSE" "FALSE" if isinstance(initial_val, bool) and not initial_val else \
else: str(initial_val)
initial_val_str = str(initial_val)
line += f' := {initial_val_str}' line += f' := {initial_val_str}'
# No añadir ; si es una declaración de STRUCT que va a tener un bloque de miembros. is_multiline_struct_def = (var_info["data_type"].upper() == "STRUCT" and \
# El ; irá después de su END_STRUCT. not var_info.get("udt_source_name") and \
if not (var_info["data_type"].upper() == "STRUCT" and var_info.get("children") and not var_info.get("udt_source_name")): var_info.get("children"))
if not is_multiline_struct_def: # Solo añadir ; si no es una cabecera de STRUCT multilínea
line += ';' line += ';'
if var_info.get("comment"): if var_info.get("comment"):
line += f'\t// {var_info["comment"]}' line += f'\t// {var_info["comment"]}'
return line return line
def generate_struct_members_for_source(members: List[Dict[str, Any]], indent_level: int) -> List[str]: def generate_struct_members_for_source(members: List[Dict[str, Any]], indent_level: int) -> List[str]:
"""Genera recursivamente las declaraciones de miembros para STRUCTs/UDTs."""
lines = [] lines = []
for var_info in members: for var_info in members:
if var_info.get("is_udt_expanded_member"): # No declarar individualmente miembros expandidos de UDT en el padre if var_info.get("is_udt_expanded_member"): continue
continue if var_info["data_type"].upper() == "STRUCT" and \
not var_info.get("udt_source_name") and \
# Si es una definición de STRUCT anidada (no una instancia de UDT) var_info.get("children"):
if var_info["data_type"].upper() == "STRUCT" and not var_info.get("udt_source_name") and var_info.get("children"):
current_indent_str = " " * indent_level current_indent_str = " " * indent_level
# La declaración "Miembro : STRUCT" no lleva ; si es multilínea. lines.append(f'{current_indent_str}{var_info["name"]} : STRUCT') # SIN ;
lines.append(f'{current_indent_str}{var_info["name"]} : STRUCT')
lines.extend(generate_struct_members_for_source(var_info["children"], indent_level + 1)) lines.extend(generate_struct_members_for_source(var_info["children"], indent_level + 1))
lines.append(f'{current_indent_str}END_STRUCT;') # ; después de END_STRUCT lines.append(f'{current_indent_str}END_STRUCT;') # CON ;
else: # Variable primitiva, String, Array, o instancia de UDT else:
lines.append(generate_variable_declaration_for_source(var_info, indent_level)) lines.append(generate_variable_declaration_for_source(var_info, indent_level))
return lines return lines
def _generate_assignments_recursive_from_current_values(members: List[Dict[str, Any]], path_prefix: str, indent_str: str) -> List[str]:
"""
Fallback recursivo para generar asignaciones del bloque BEGIN usando current_value y current_element_values.
Este se usa si _initial_values_from_begin_block no está en el JSON.
"""
assignment_lines = []
for var_info in members:
current_member_name = var_info['name']
current_full_path = f"{path_prefix}{current_member_name}"
if var_info.get("current_element_values") and isinstance(var_info["current_element_values"], dict):
# Ordenar por índice para consistencia si los índices son numéricos simples
# La clave 'index_str' podría ser "1" o "1,0" etc.
try:
# Intenta convertir la clave a una tupla de enteros para un ordenamiento numérico robusto
sorted_indices = sorted(
var_info["current_element_values"].keys(),
key=lambda k: tuple(map(int, k.split(',')))
)
except ValueError: # Si las claves no son puramente numéricas/separadas por comas
sorted_indices = sorted(var_info["current_element_values"].keys())
for index_str in sorted_indices:
val_str_el = var_info["current_element_values"][index_str]
el_path = f"{current_full_path}[{index_str}]"
f_val_str_el = str(val_str_el)
if f_val_str_el.lower() == "true": f_val_str_el = "TRUE"
elif f_val_str_el.lower() == "false": f_val_str_el = "FALSE"
assignment_lines.append(f"{indent_str}{el_path} := {f_val_str_el};")
elif var_info.get("udt_source_name") and var_info.get("children"):
assignment_lines.extend(_generate_assignments_recursive_from_current_values(var_info["children"], f"{current_full_path}.", indent_str))
elif var_info.get("data_type", "").upper() == "STRUCT" and not var_info.get("udt_source_name") and var_info.get("children"):
assignment_lines.extend(_generate_assignments_recursive_from_current_values(var_info["children"], f"{current_full_path}.", indent_str))
elif var_info.get("current_value") is not None:
val_str_cv = var_info["current_value"]
f_val_str_cv = str(val_str_cv)
if f_val_str_cv.lower() == "true": f_val_str_cv = "TRUE"
elif f_val_str_cv.lower() == "false": f_val_str_cv = "FALSE"
assignment_lines.append(f"{indent_str}{current_full_path} := {f_val_str_cv};")
return assignment_lines
def generate_begin_block_assignments(db_info: Dict[str, Any], indent_level: int) -> List[str]: def generate_begin_block_assignments(db_info: Dict[str, Any], indent_level: int) -> List[str]:
"""Genera las líneas de asignación para el bloque BEGIN de un DB."""
indent_str = " " * indent_level indent_str = " " * indent_level
lines = [] lines = []
# Usar la lista ordenada de asignaciones del JSON, que x3.py ahora debería poblar
ordered_assignments = db_info.get("_begin_block_assignments_ordered")
# Prioridad: Usar _initial_values_from_begin_block si está presente en el JSON if ordered_assignments and isinstance(ordered_assignments, list):
# ¡ASEGÚRATE DE QUE x3.py INCLUYA ESTE CAMPO EN EL JSON (modificando custom_json_serializer en x3.py)! print(f"INFO: Usando '_begin_block_assignments_ordered' para generar bloque BEGIN de DB '{db_info['name']}'.")
begin_values_map = db_info.get("_initial_values_from_begin_block") for path, value_obj in ordered_assignments:
value_str = str(value_obj)
if begin_values_map and isinstance(begin_values_map, dict): if value_str.lower() == "true": value_str = "TRUE"
print(f"INFO: Usando _initial_values_from_begin_block para DB '{db_info['name']}' en el bloque BEGIN.") elif value_str.lower() == "false": value_str = "FALSE"
# Ordenar por clave para una salida más consistente. lines.append(f"{indent_str}{path} := {value_str};") # Asignaciones siempre con ;
# El orden original del bloque BEGIN en el archivo fuente es difícil de replicar sin información adicional.
for path, value_obj in sorted(begin_values_map.items()):
value_str = str(value_obj) # Asegurar que el valor es una cadena
# S7 convierte true/false de JSON a TRUE/FALSE en el fuente.
if value_str.lower() == "true":
value_str = "TRUE"
elif value_str.lower() == "false":
value_str = "FALSE"
# Otros tipos como B#16#XX, W#16#YYYY, L#... etc., deberían estar ya como strings.
lines.append(f"{indent_str}{path} := {value_str};")
else: else:
# Fallback: si _initial_values_from_begin_block no está, intentar reconstruir desde current_value/current_element_values print(f"ADVERTENCIA: '_begin_block_assignments_ordered' no encontrado para DB '{db_info['name']}'. "
# Esto depende de que x3.py haya poblado bien estos campos. "El bloque BEGIN puede estar incompleto o desordenado si se usa el fallback.")
print(f"ADVERTENCIA: _initial_values_from_begin_block no encontrado o vacío para DB '{db_info['name']}'. " # (Aquí podría ir el fallback a _generate_assignments_recursive_from_current_values si se desea)
"Intentando reconstruir el bloque BEGIN desde current_value/current_element_values.") # fallback_lines = _generate_assignments_recursive_from_current_values(db_info.get("members", []), "", indent_str)
lines.extend(_generate_assignments_recursive_from_current_values(db_info.get("members", []), "", indent_str)) # if fallback_lines: lines.extend(fallback_lines)
return lines return lines
def generate_s7_source_code_lines(data: Dict[str, Any]) -> List[str]: def generate_s7_source_code_lines(data: Dict[str, Any]) -> List[str]:
"""Genera el código fuente S7 completo (UDTs y DBs) a partir de los datos JSON."""
lines = [] lines = []
parsed_json_udts_lookup = {udt['name']: udt for udt in data.get("udts", [])} # Necesario para algunas lógicas internas
# Generar UDTs
for udt in data.get("udts", []): for udt in data.get("udts", []):
lines.append(f'TYPE "{udt["name"]}"') lines.append(f'TYPE "{udt["name"]}"')
if udt.get("family"): lines.append(f' FAMILY : {udt["family"]};') if udt.get("family"): lines.append(f' FAMILY : {udt["family"]}') # SIN ;
if udt.get("version"): lines.append(f' VERSION : {udt["version"]};') if udt.get("version"): lines.append(f' VERSION : {udt["version"]}') # SIN ;
lines.append("") lines.append("")
lines.append(" STRUCT") # El keyword STRUCT en sí no lleva ; lines.append(" STRUCT") # SIN ;
lines.extend(generate_struct_members_for_source(udt["members"], 2)) lines.extend(generate_struct_members_for_source(udt["members"], 2))
lines.append(" END_STRUCT;") lines.append(" END_STRUCT;") # CON ;
lines.append(f'END_TYPE;') lines.append(f'END_TYPE') # SIN ; según tu último comentario
lines.append("") lines.append("")
# Generar DBs
for db in data.get("dbs", []): for db in data.get("dbs", []):
lines.append(f'DATA_BLOCK "{db["name"]}"') lines.append(f'DATA_BLOCK "{db["name"]}"')
if db.get("title"): # TITLE = { ... } va tal cual y SIN ;
# Reconstruir TITLE si existe en el JSON lines.append(f' TITLE = {db["title"]}')
if db.get("title"): if db.get("family"): lines.append(f' FAMILY : {db["family"]}') # SIN ;
title_str = db["title"] if db.get("version"): lines.append(f' VERSION : {db["version"]}') # SIN ;
# El formato original es TITLE = y luego el valor, usualmente una estructura { S7_language... }
# No se añade punto y coma a esta línea específica.
lines.append(f' TITLE = {title_str}')
if db.get("family"): lines.append(f' FAMILY : {db["family"]};')
if db.get("version"): lines.append(f' VERSION : {db["version"]};')
lines.append("") lines.append("")
lines.append(" STRUCT") # El keyword STRUCT en sí no lleva ; lines.append(" STRUCT") # SIN ;
lines.extend(generate_struct_members_for_source(db["members"], 2)) lines.extend(generate_struct_members_for_source(db["members"], 2))
lines.append(" END_STRUCT;") lines.append(" END_STRUCT;") # CON ;
begin_assignments = generate_begin_block_assignments(db, 1) # Pasar parsed_json_udts_lookup si es necesario en el futuro begin_assignments = generate_begin_block_assignments(db, 1) # Indentación 1 para las asignaciones
if begin_assignments: if begin_assignments:
lines.append("BEGIN") lines.append("BEGIN") # SIN ;
lines.extend(begin_assignments) lines.extend(begin_assignments)
lines.append(f'END_DATA_BLOCK;') lines.append(f'END_DATA_BLOCK') # SIN ; según tu último comentario
lines.append("") lines.append("")
return lines return lines
# --- generate_markdown_table (sin cambios significativos respecto a la v3, pero puedes revisarla) --- # generate_markdown_table (sin cambios respecto a la v5)
def generate_markdown_table(db_info: Dict[str, Any]) -> List[str]: def generate_markdown_table(db_info: Dict[str, Any]) -> List[str]:
lines = [] lines = []
lines.append(f"# Documentación para DB: {db_info['name']}") lines.append(f"# Documentación para DB: {db_info['name']}")
lines.append("") lines.append("")
lines.append("| Address | Name | Type | Initial Value | Actual Value | Comment |") lines.append("| Address | Name | Type | Initial Value | Actual Value | Comment |")
lines.append("|---|---|---|---|---|---|") lines.append("|---|---|---|---|---|---|")
processed_expanded_members = set() processed_expanded_members = set()
def flatten_members_for_markdown(members: List[Dict[str, Any]], prefix: str = "", base_offset: float = 0.0, is_expansion: bool = False): def flatten_members_for_markdown(members: List[Dict[str, Any]], prefix: str = "", base_offset: float = 0.0, is_expansion: bool = False):
md_lines = [] md_lines = []
for var_idx, var in enumerate(members): for var_idx, var in enumerate(members):
member_id = f"{prefix}{var['name']}_{var_idx}" member_id = f"{prefix}{var['name']}_{var_idx}"
if is_expansion and member_id in processed_expanded_members: continue
if is_expansion and member_id in processed_expanded_members: if is_expansion: processed_expanded_members.add(member_id)
continue
if is_expansion:
processed_expanded_members.add(member_id)
name_for_display = f"{prefix}{var['name']}" name_for_display = f"{prefix}{var['name']}"
address = f"{var['byte_offset']:.1f}" if isinstance(var['byte_offset'], float) else str(var['byte_offset']) address = f"{var['byte_offset']:.1f}" if isinstance(var['byte_offset'], float) else str(var['byte_offset'])
if var.get("bit_size", 0) > 0 and isinstance(var['byte_offset'], float) and var['byte_offset'] != int(var['byte_offset']): if var.get("bit_size", 0) > 0 and isinstance(var['byte_offset'], float) and var['byte_offset'] != int(var['byte_offset']): pass
pass elif var.get("bit_size", 0) > 0 : address = f"{int(var['byte_offset'])}.0"
elif var.get("bit_size", 0) > 0 :
address = f"{int(var['byte_offset'])}.0"
data_type_str = format_data_type_for_source(var) data_type_str = format_data_type_for_source(var)
initial_value = str(var.get("initial_value", "")) initial_value = str(var.get("initial_value", "")).replace("|", "\\|").replace("\n", " ")
actual_value = str(var.get("current_value", "")) actual_value = str(var.get("current_value", "")).replace("|", "\\|").replace("\n", " ")
comment = str(var.get("comment", "")) comment = str(var.get("comment", "")).replace("|", "\\|").replace("\n", " ")
initial_value = initial_value.replace("|", "\\|")
actual_value = actual_value.replace("|", "\\|")
comment = comment.replace("|", "\\|").replace("\n", " ")
is_struct_container = var["data_type"].upper() == "STRUCT" and not var.get("udt_source_name") and var.get("children") is_struct_container = var["data_type"].upper() == "STRUCT" and not var.get("udt_source_name") and var.get("children")
is_udt_instance_container = bool(var.get("udt_source_name")) and var.get("children") is_udt_instance_container = bool(var.get("udt_source_name")) and var.get("children")
if not is_struct_container and not is_udt_instance_container or var.get("is_udt_expanded_member"): if not is_struct_container and not is_udt_instance_container or var.get("is_udt_expanded_member"):
md_lines.append(f"| {address} | {name_for_display} | {data_type_str} | {initial_value} | {actual_value} | {comment} |") md_lines.append(f"| {address} | {name_for_display} | {data_type_str} | {initial_value} | {actual_value} | {comment} |")
if var.get("children"): if var.get("children"):
md_lines.extend(flatten_members_for_markdown(var["children"], md_lines.extend(flatten_members_for_markdown(var["children"],
f"{name_for_display}.", f"{name_for_display}.",
var['byte_offset'], var['byte_offset'],
is_expansion=bool(var.get("udt_source_name")))) is_expansion=bool(var.get("udt_source_name"))))
return md_lines return md_lines
lines.extend(flatten_members_for_markdown(db_info.get("members", []))) lines.extend(flatten_members_for_markdown(db_info.get("members", [])))
return lines return lines
def main(): def main():
# Asegúrate que este es el JSON generado por la última versión de x3.py json_input_filename = "parsed_s7_data_stat.json" # Espera el JSON de x3_v_final_2
# (la que incluye _initial_values_from_begin_block y current_element_values) s7_output_filename = "reconstructed_s7_source_stat.txt"
json_input_filename = "parsed_s7_data.json"
s7_output_filename = "reconstructed_s7_source.txt" # Nueva versión de salida
try: try:
with open(json_input_filename, 'r', encoding='utf-8') as f: with open(json_input_filename, 'r', encoding='utf-8') as f: data_from_json = json.load(f)
data_from_json = json.load(f) print(f"Archivo JSON '{json_input_filename}' cargado correctamente.")
except FileNotFoundError:
print(f"Error: No se encontró el archivo JSON de entrada: {json_input_filename}")
return
except json.JSONDecodeError:
print(f"Error: El archivo JSON de entrada no es válido: {json_input_filename}")
return
except Exception as e: except Exception as e:
print(f"Error al leer el archivo JSON {json_input_filename}: {e}") print(f"Error al cargar/leer {json_input_filename}: {e}"); return
return
print(f"Archivo JSON '{json_input_filename}' cargado correctamente.") s7_code_lines = generate_s7_source_code_lines(data_from_json)
# CORRECCIÓN DEL ERROR: Pasar el argumento faltante
s7_code_lines = generate_s7_source_code_lines(data_from_json) # parsed_json_udts se crea dentro ahora
try: try:
with open(s7_output_filename, 'w', encoding='utf-8') as f: with open(s7_output_filename, 'w', encoding='utf-8') as f:
for line in s7_code_lines: for line in s7_code_lines: f.write(line + "\n")
f.write(line + "\n")
print(f"Archivo S7 reconstruido generado: {s7_output_filename}") print(f"Archivo S7 reconstruido generado: {s7_output_filename}")
except Exception as e: except Exception as e: print(f"Error al escribir el archivo S7 {s7_output_filename}: {e}")
print(f"Error al escribir el archivo S7 {s7_output_filename}: {e}")
if data_from_json.get("dbs"): if data_from_json.get("dbs"):
for db_to_document in data_from_json["dbs"]: for db_to_document in data_from_json["dbs"]:
db_name_safe = db_to_document['name'].replace('"', '').replace(' ', '_').replace('/','_') db_name_safe = db_to_document['name'].replace('"', '').replace(' ', '_').replace('/','_')
md_filename_specific = f"documentation_db_{db_name_safe}.md" # Nuevo nombre md_filename_specific = f"documentation_db_{db_name_safe}.md"
print(f"\nGenerando documentación Markdown para DB: {db_to_document['name']}...") print(f"\nGenerando documentación Markdown para DB: {db_to_document['name']}...")
markdown_lines = generate_markdown_table(db_to_document) markdown_lines = generate_markdown_table(db_to_document)
try: try:
with open(md_filename_specific, 'w', encoding='utf-8') as f: with open(md_filename_specific, 'w', encoding='utf-8') as f:
for line in markdown_lines: for line in markdown_lines: f.write(line + "\n")
f.write(line + "\n")
print(f"Archivo Markdown de documentación generado: {md_filename_specific}") print(f"Archivo Markdown de documentación generado: {md_filename_specific}")
except Exception as e: except Exception as e: print(f"Error al escribir {md_filename_specific}: {e}")
print(f"Error al escribir el archivo Markdown {md_filename_specific}: {e}") else: print("No se encontraron DBs en el archivo JSON para generar documentación.")
else:
print("No se encontraron DBs en el archivo JSON para generar documentación.")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -0,0 +1,192 @@
import json
from typing import List, Dict, Any, Optional
def format_data_type_for_display(var_info: Dict[str, Any]) -> str:
"""Formatea la declaración de tipo para visualización en Markdown."""
base_type = var_info.get("udt_source_name") if var_info.get("udt_source_name") else var_info["data_type"]
type_str = ""
if var_info.get("array_dimensions"):
dims_str = ",".join([f"{d['lower_bound']}..{d['upper_bound']}" for d in var_info["array_dimensions"]])
type_str += f"ARRAY [{dims_str}] OF "
type_str += base_type
if var_info["data_type"].upper() == "STRING" and var_info.get("string_length") is not None:
type_str += f"[{var_info['string_length']}]"
return type_str
def format_offset_for_display(byte_offset: float) -> str:
"""Formatea el offset como X.Y o solo X si es .0."""
if byte_offset == float(int(byte_offset)):
return str(int(byte_offset))
return f"{byte_offset:.1f}"
def generate_members_table_md(
members: List[Dict[str, Any]],
path_prefix: str = "",
is_udt_definition: bool = False,
include_current_value: bool = False
) -> List[str]:
"""Genera líneas de tabla Markdown para una lista de miembros."""
md_lines = []
for var_info in members:
name_display = f"{path_prefix}{var_info['name']}"
# Para miembros expandidos de un UDT, su nombre ya está completo en la jerarquía del JSON.
# La recursión ya habrá construido el path_prefix.
# No necesitamos hacer nada especial aquí si `is_udt_expanded_member` es true,
# ya que esta función se llama recursivamente sobre `children`.
data_type_display = format_data_type_for_display(var_info)
offset_display = format_offset_for_display(var_info['byte_offset'])
size_bytes_display = str(var_info['size_in_bytes'])
bit_size_display = str(var_info.get('bit_size', '0')) if var_info.get('bit_size', 0) > 0 else ""
initial_value_display = str(var_info.get('initial_value', '')).replace("|", "\\|").replace("\n", " ")
comment_display = str(var_info.get('comment', '')).replace("|", "\\|").replace("\n", " ")
row = f"| `{name_display}` | `{data_type_display}` | {offset_display} | {size_bytes_display} | {bit_size_display} | `{initial_value_display}` |"
if include_current_value:
current_value_display = ""
# Si es un array y tiene current_element_values
if var_info.get("current_element_values") and isinstance(var_info["current_element_values"], dict):
# Mostrar un resumen o un placeholder para arrays complejos en la tabla principal
# Los valores detallados del array se listarán en la sección BEGIN.
num_elements = sum(dim['count'] for dim in var_info.get('array_dimensions', [])) if var_info.get('array_dimensions') else 1
if num_elements == 0 and var_info.get("array_dimensions"): # Caso de ARRAY [x..y] donde x > y (raro, pero posible)
num_elements = 1 # Para evitar división por cero o lógica extraña.
assigned_elements = len(var_info["current_element_values"])
if assigned_elements > 0:
current_value_display = f"{assigned_elements} elemento(s) asignado(s) en BEGIN"
elif var_info.get("current_value") is not None: # Para arrays con una asignación global (raro en BEGIN)
current_value_display = str(var_info.get("current_value", '')).replace("|", "\\|").replace("\n", " ")
else:
current_value_display = ""
elif var_info.get("current_value") is not None:
current_value_display = str(var_info.get("current_value", '')).replace("|", "\\|").replace("\n", " ")
row += f" `{current_value_display}` |"
row += f" {comment_display} |"
md_lines.append(row)
# Recursión para hijos de STRUCTs o miembros expandidos de UDTs
# `is_udt_expanded_member` en el JSON nos dice si los 'children' son la expansión de un UDT.
if var_info.get("children"):
# El prefijo para los hijos es el nombre completo del padre actual.
# Si el hijo es un miembro expandido de UDT, su propio nombre en 'children' ya es el nombre final del miembro.
# Si el hijo es parte de un STRUCT anidado, su nombre es relativo al STRUCT.
md_lines.extend(generate_members_table_md(
var_info["children"],
f"{name_display}.",
is_udt_definition,
include_current_value
))
return md_lines
def generate_json_documentation(data: Dict[str, Any], output_filename: str):
"""Genera la documentación Markdown completa para el archivo JSON parseado."""
lines = []
lines.append(f"# Documentación del Archivo de Datos S7 Parseado")
current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
lines.append(f"_Generado el: {current_date}_")
lines.append("")
lines.append("Este documento describe la estructura y el contenido del archivo JSON generado por el parser de fuentes S7 (`x3.py`).")
lines.append("")
# --- Sección UDTs ---
lines.append("## 1. Tipos de Datos de Usuario (UDTs)")
lines.append("")
if data.get("udts"):
for udt in data["udts"]:
lines.append(f'### 1.{data["udts"].index(udt) + 1}. UDT: `{udt["name"]}`')
if udt.get("family"): lines.append(f"- **Familia**: {udt['family']}")
if udt.get("version"): lines.append(f"- **Versión**: {udt['version']}")
lines.append(f"- **Tamaño Total**: {udt['total_size_in_bytes']} bytes")
lines.append("")
lines.append("#### Miembros del UDT:")
lines.append("| Nombre Miembro | Tipo de Dato | Offset (Byte.Bit) | Tamaño (Bytes) | Tamaño (Bits) | Valor Inicial | Comentario |")
lines.append("|---|---|---|---|---|---|---|")
lines.extend(generate_members_table_md(udt.get("members", []), is_udt_definition=True, include_current_value=False))
lines.append("")
else:
lines.append("No se encontraron UDTs en el archivo JSON.")
lines.append("")
# --- Sección DBs ---
lines.append("## 2. Bloques de Datos (DBs)")
lines.append("")
if data.get("dbs"):
for db in data["dbs"]:
lines.append(f'### 2.{data["dbs"].index(db) + 1}. DB: `{db["name"]}`')
if db.get("title"): lines.append(f"- **TITLE**: `{db['title']}`")
if db.get("family"): lines.append(f"- **Familia**: {db['family']}")
if db.get("version"): lines.append(f"- **Versión**: {db['version']}")
lines.append(f"- **Tamaño Declaraciones**: {db['total_size_in_bytes']} bytes")
lines.append("")
lines.append("#### Miembros del DB (Sección de Declaración):")
lines.append("| Nombre Miembro (Ruta) | Tipo de Dato | Offset (Byte.Bit) | Tamaño (Bytes) | Tamaño (Bits) | Valor Inicial (Decl.) | Valor Actual (Efectivo) | Comentario |")
lines.append("|---|---|---|---|---|---|---|---|")
lines.extend(generate_members_table_md(db.get("members", []), include_current_value=True))
lines.append("")
# Sección BEGIN
ordered_assignments = db.get("_begin_block_assignments_ordered")
if ordered_assignments:
lines.append("#### Contenido del Bloque `BEGIN` (Valores Actuales Asignados):")
lines.append("El bloque `BEGIN` define los valores actuales de las variables en el DB. Las siguientes asignaciones fueron encontradas, en orden:")
lines.append("")
lines.append("```scl") # Usar SCL para syntax highlighting si el visualizador Markdown lo soporta
for path, value in ordered_assignments:
val_str = str(value)
if val_str.lower() == "true": val_str = "TRUE"
elif val_str.lower() == "false": val_str = "FALSE"
lines.append(f" {path} := {val_str};")
lines.append("```")
lines.append("")
else:
lines.append("No se encontraron asignaciones en el bloque `BEGIN` (o no fue parseado).")
lines.append("")
else:
lines.append("No se encontraron DBs en el archivo JSON.")
# Guardar el archivo Markdown
try:
with open(output_filename, 'w', encoding='utf-8') as f:
for line in lines:
f.write(line + "\n")
print(f"Documentación Markdown completa generada: {output_filename}")
except Exception as e:
print(f"Error al escribir el archivo Markdown de documentación {output_filename}: {e}")
# --- Main ---
if __name__ == "__main__":
from datetime import datetime # Mover import aquí
# Asume que el JSON es generado por la última versión de x3.py
# (ej. parsed_s7_data_x3_v_final_3.json o el nombre que uses)
json_input_filename = "parsed_s7_data.json"
markdown_output_filename = "documentacion_json_s7.md"
try:
with open(json_input_filename, 'r', encoding='utf-8') as f:
data_from_json = json.load(f)
print(f"Archivo JSON '{json_input_filename}' cargado correctamente.")
except FileNotFoundError:
print(f"Error: No se encontró el archivo JSON de entrada: {json_input_filename}")
exit()
except json.JSONDecodeError:
print(f"Error: El archivo JSON de entrada no es válido: {json_input_filename}")
exit()
except Exception as e:
print(f"Error al leer el archivo JSON {json_input_filename}: {e}")
exit()
generate_json_documentation(data_from_json, markdown_output_filename)