Compare commits
3 Commits
0ddee2e14a
...
b67851e615
Author | SHA1 | Date |
---|---|---|
|
b67851e615 | |
|
9e7e310384 | |
|
57ca21ec76 |
|
@ -1,81 +0,0 @@
|
||||||
{
|
|
||||||
"block_name": "FC General Lamp",
|
|
||||||
"block_number": 172,
|
|
||||||
"language": "LAD",
|
|
||||||
"block_type": "FC",
|
|
||||||
"block_comment": "",
|
|
||||||
"interface": {
|
|
||||||
"Return": [
|
|
||||||
{
|
|
||||||
"name": "Ret_Val",
|
|
||||||
"datatype": "Void",
|
|
||||||
"remanence": "NonRetain",
|
|
||||||
"accessibility": "Public",
|
|
||||||
"start_value": null,
|
|
||||||
"comment": null,
|
|
||||||
"children": [],
|
|
||||||
"array_elements": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"networks": [
|
|
||||||
{
|
|
||||||
"id": "4",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Light Green",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "B",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Light Red",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "12",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Buzzer",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "19",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Light Blue",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "20",
|
|
||||||
"title": "Lamp - Alarm Presence",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "27",
|
|
||||||
"title": "Light Signal Phased Stop Machine",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2E",
|
|
||||||
"title": "",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source_xml_mod_time": 1749751920.2702959,
|
|
||||||
"source_xml_size": 39346
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,81 +0,0 @@
|
||||||
{
|
|
||||||
"block_name": "FC General Lamp",
|
|
||||||
"block_number": 172,
|
|
||||||
"language": "LAD",
|
|
||||||
"block_type": "FC",
|
|
||||||
"block_comment": "",
|
|
||||||
"interface": {
|
|
||||||
"Return": [
|
|
||||||
{
|
|
||||||
"name": "Ret_Val",
|
|
||||||
"datatype": "Void",
|
|
||||||
"remanence": "NonRetain",
|
|
||||||
"accessibility": "Public",
|
|
||||||
"start_value": null,
|
|
||||||
"comment": null,
|
|
||||||
"children": [],
|
|
||||||
"array_elements": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"networks": [
|
|
||||||
{
|
|
||||||
"id": "4",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Light Green",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "B",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Light Red",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "12",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Buzzer",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "19",
|
|
||||||
"title": "Lamp Alarm - Q.E. - Light Blue",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "20",
|
|
||||||
"title": "Lamp - Alarm Presence",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "27",
|
|
||||||
"title": "Light Signal Phased Stop Machine",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2E",
|
|
||||||
"title": "",
|
|
||||||
"comment": "",
|
|
||||||
"language": "LAD",
|
|
||||||
"logic": [],
|
|
||||||
"error": "FlgNet not found inside NetworkSource or CompileUnit"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source_xml_mod_time": 1749751920.2702959,
|
|
||||||
"source_xml_size": 39346
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,178 @@
|
||||||
|
// Block Type: FC
|
||||||
|
// Block Name (Original): FC TT Devices
|
||||||
|
// Block Number: 380
|
||||||
|
// Original Network Languages: SCL, LAD, STL
|
||||||
|
|
||||||
|
FUNCTION "FC_TT_Devices" : Void
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
YLBR1 : Bool;
|
||||||
|
YLBR2 : Bool;
|
||||||
|
YLBR3 : Bool;
|
||||||
|
YLBR4 : Bool;
|
||||||
|
YLBR5 : Bool;
|
||||||
|
SystemReady : Bool;
|
||||||
|
ConveyorsRunning : Bool;
|
||||||
|
Filler_Run : Bool;
|
||||||
|
Labeller_Run : Bool;
|
||||||
|
Line_Empty : Bool;
|
||||||
|
Reset_Push_Button : Bool;
|
||||||
|
Line_Empty : Bool;
|
||||||
|
DUMMY : Bool;
|
||||||
|
LEVEL_OK : Bool;
|
||||||
|
Temp : Bool;
|
||||||
|
Ap_HighLim : Real;
|
||||||
|
Ap_LowLim : Real;
|
||||||
|
Apoyo_Rechazo : Bool;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
#_0 : Bool; // Auto-generated temporary
|
||||||
|
#_1500ms : Bool; // Auto-generated temporary
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
// Network 1: EMD - Body Guide (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB TTOP - Body Guide EMD"(Number_Zone := 4, Pressure_Control_Zone_1 := "P1-M37" AND NOT "DB TT Alarm"."A371_04_0", Pressure_Control_Zone_2 := "P1-M39" AND NOT "DB TT Alarm"."A371_04_1", Pressure_Control_Zone_3 := "P1-M41" AND NOT "DB TT Alarm"."A371_04_2", Pressure_Control_Zone_4 := "P1-M42" AND NOT "DB TT Alarm"."A371_04_3", Pressure_Control_Zone_5 := FALSE);
|
||||||
|
|
||||||
|
// Network 2: Elevator Door Management - UpStair (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Door Control - Lifter - UpStair"(BUTTON_REQUEST := "E7.2", CLK_FAST := "M1.3", CLK_SLOW := "M1.5", DOOR_OPEN := "E7.6" OR "E7.7" OR NOT "KS165-1C", FBK_MACHINE_OFF := Eq("DB TT Motor 35"."Manage"."STATUS_VFD_ACT_Speed_Hz", 0));
|
||||||
|
|
||||||
|
// Network 3: Elevator Door Management - DownStair (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Door Control - Lifter - DownStair"(BUTTON_REQUEST := "E7.0", CLK_FAST := "M1.3", CLK_SLOW := "M1.5", DOOR_OPEN := "E7.4" OR "E7.5" OR NOT "KS165-1C", FBK_MACHINE_OFF := Eq("DB TT Motor 35"."Manage"."STATUS_VFD_ACT_Speed_Hz", 0));
|
||||||
|
|
||||||
|
// Network 4: Elevator - Right/ Left Control breaking chains (Original Language: LAD)
|
||||||
|
|
||||||
|
"Timer_Chain_Right"(IN := NOT "S1-M35", PT := S5T#1500ms); // TODO: Declarar "Timer_Chain_Right" : TON;
|
||||||
|
|
||||||
|
"Timer_Chain_Left"(IN := NOT "S2-M35", PT := S5T#1500ms); // TODO: Declarar "Timer_Chain_Left" : TON;
|
||||||
|
|
||||||
|
// Network 5: Energy Saving - Line Empty (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 5 ---
|
||||||
|
```stl
|
||||||
|
A "B1-M31"
|
||||||
|
A "B1-M32"
|
||||||
|
A "B2-M32"
|
||||||
|
A "B1-M34"
|
||||||
|
A "B2-M34"
|
||||||
|
A "B1-M35"
|
||||||
|
A "B2-M35"
|
||||||
|
A "B4-M35"
|
||||||
|
A "B5-M35"
|
||||||
|
A "B1-M36"
|
||||||
|
A "B1-M37"
|
||||||
|
A "B2-M37"
|
||||||
|
A "B1-M38"
|
||||||
|
A "B2-M38"
|
||||||
|
A "B1-M39"
|
||||||
|
A "B2-M39"
|
||||||
|
A "B1-M40"
|
||||||
|
A "B2-M40"
|
||||||
|
A "B1-M41"
|
||||||
|
A "B2-M41"
|
||||||
|
A "B1-M42"
|
||||||
|
A "B2-M42"
|
||||||
|
= "Line Empty"
|
||||||
|
```
|
||||||
|
// --- END STL Network 5 ---
|
||||||
|
|
||||||
|
// Network 6: Energy Saving (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB TTOP - Energy Saving"(DownStream_Mac_Req := "M0.1" OR ("DB Signal DownStream Machine - TL25_Q2"."IN_DIG_Signal_01" AND "M0.0"), Sensor_on_the_line := "Line Empty", UpStream_Mac_Empty := "DB TT Run"."TT_Run"."OUT_Cycle_ON" AND (("ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X00" AND "ComSV"."TL25_ReadFromSv"."FromSV"."Data From TL28"."Run") OR (NOT "ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X00" AND NOT "ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X13" AND NOT "ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X14")));
|
||||||
|
|
||||||
|
// Network 7: Bottle Counter M153_154 (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Bottle Counter M153_154"(Conveyor_Running := "DB TT Motor 41"."Manage"."STATUS_VFD_Run_FWD" AND "DB TT Motor 42"."Manage"."STATUS_VFD_Run_FWD", PH_Inlet := "Count 1 M42", PH_Outlet := "Count 2 M42", Reset_Button_Allarm := "SH331-1B", Reset_Counter_Henkel := "ComSV"."TL25_WriteToSv"."FromHenkel"."STW"."di0.x");
|
||||||
|
|
||||||
|
// Network 8: Bottle Counter M37 (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Bottle Counter_M37"(Conveyor_Running := "DB TT Motor 37"."Manage"."STATUS_VFD_Run_FWD", PH_Inlet := "Count 1 M35", PH_Outlet := "Count 2 M35", Reset_Button_Allarm := "SH331-1B", Reset_Counter_Henkel := "ComSV"."TL25_WriteToSv"."FromHenkel"."STW"."di0.x");
|
||||||
|
|
||||||
|
IF "M0.1" THEN
|
||||||
|
"DB TT Alarm"."A371_03_3" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 9: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "Tag_27" > 5 THEN
|
||||||
|
"Tag_27" := 0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"Apoyo_Rechazo" := "B5-M35" OR ("M0.0" AND Eq("Tag_27", 5));
|
||||||
|
|
||||||
|
// Network 10: Ejector Bottle (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 10 ---
|
||||||
|
```stl
|
||||||
|
CALL "DB Ejector Bottle"
|
||||||
|
```
|
||||||
|
// --- END STL Network 10 ---
|
||||||
|
|
||||||
|
// Network 11: Photocell Teach (Original Language: LAD)
|
||||||
|
|
||||||
|
"Delay Photocell Teach"(IN := "DB General"."X203_0", PT := S5T#0.8s); // TODO: Declarar "Delay Photocell Teach" : TP;
|
||||||
|
|
||||||
|
"A8.0" := "Delay Photocell Teach".Q;
|
||||||
|
|
||||||
|
"DB General"."X203_1" := "Delay Photocell Teach".Q;
|
||||||
|
|
||||||
|
IF "Delay Photocell Teach".Q THEN
|
||||||
|
"DB General"."X203_0" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 12: Elevator - Guide (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 12 ---
|
||||||
|
```stl
|
||||||
|
CALL "DB Guide Lifter - Lowerator"
|
||||||
|
```
|
||||||
|
// --- END STL Network 12 ---
|
||||||
|
|
||||||
|
// Network 13: Elevator - Lube (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 13 ---
|
||||||
|
```stl
|
||||||
|
|
||||||
|
CALL "DB lube M35"
|
||||||
|
```
|
||||||
|
// --- END STL Network 13 ---
|
||||||
|
|
||||||
|
// Network 14: Camera Ejector Bottle (Original Language: STL)
|
||||||
|
// "E38.1"
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 14 ---
|
||||||
|
```stl
|
||||||
|
CALL "DB Camera Ejector Bottle"
|
||||||
|
```
|
||||||
|
// --- END STL Network 14 ---
|
||||||
|
|
||||||
|
// Network 15: (Original Language: LAD)
|
||||||
|
|
||||||
|
// Network 15 did not produce printable SCL code.
|
||||||
|
|
||||||
|
// Network 16: Elevator - SV Reject Y1-M35 (Original Language: LAD)
|
||||||
|
|
||||||
|
"Y1-M35" := "Ejector_Tower" OR "Ejector_Camera";
|
||||||
|
|
||||||
|
// Network 17: Signal for changeover done (Original Language: LAD)
|
||||||
|
|
||||||
|
"Ap_EMD_InPsosition" := Eq("DB TTOP - Body Guide EMD"."Counter_Position", "DB TTOP - Body Guide EMD"."Position_Selection");
|
||||||
|
|
||||||
|
"Ap_HighLim" := ("DB Guide Lifter - Lowerator"."Position Selection") + ("DB Guide Lifter - Lowerator"."Range Position");
|
||||||
|
|
||||||
|
"Ap_LowLim" := ("DB Guide Lifter - Lowerator"."Position Selection") - ("DB Guide Lifter - Lowerator"."Range Position");
|
||||||
|
|
||||||
|
"Ap_LifterGuideInPositon" := "DB Guide Lifter - Lowerator"."Actual Position" >= "Ap_LowLim";
|
||||||
|
|
||||||
|
// Network 18: INTERLOCK EMD CHANGEOVER (Original Language: SCL)
|
||||||
|
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X13 := "ComSV".TL25_ReadFromSv.FromSV.STW.X06;
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X14 := "ComSV".TL25_ReadFromSv.FromSV.STW.X07;
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X15 := "ComSV".TL25_ReadFromSv.FromSV.STW.X08;
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X16 := "ComSV".TL25_ReadFromSv.FromSV.STW.X09;
|
||||||
|
|
||||||
|
END_FUNCTION
|
|
@ -0,0 +1,178 @@
|
||||||
|
// Block Type: FC
|
||||||
|
// Block Name (Original): FC TT Devices
|
||||||
|
// Block Number: 380
|
||||||
|
// Original Network Languages: SCL, STL, LAD
|
||||||
|
|
||||||
|
FUNCTION "FC_TT_Devices" : Void
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
YLBR1 : Bool;
|
||||||
|
YLBR2 : Bool;
|
||||||
|
YLBR3 : Bool;
|
||||||
|
YLBR4 : Bool;
|
||||||
|
YLBR5 : Bool;
|
||||||
|
SystemReady : Bool;
|
||||||
|
ConveyorsRunning : Bool;
|
||||||
|
Filler_Run : Bool;
|
||||||
|
Labeller_Run : Bool;
|
||||||
|
Line_Empty : Bool;
|
||||||
|
Reset_Push_Button : Bool;
|
||||||
|
Line_Empty : Bool;
|
||||||
|
DUMMY : Bool;
|
||||||
|
LEVEL_OK : Bool;
|
||||||
|
Temp : Bool;
|
||||||
|
Ap_HighLim : Real;
|
||||||
|
Ap_LowLim : Real;
|
||||||
|
Apoyo_Rechazo : Bool;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
#_0 : Bool; // Auto-generated temporary
|
||||||
|
#_1500ms : Bool; // Auto-generated temporary
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
// Network 1: EMD - Body Guide (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB TTOP - Body Guide EMD"(Number_Zone := 4, Pressure_Control_Zone_1 := "P1-M37" AND NOT "DB TT Alarm"."A371_04_0", Pressure_Control_Zone_2 := "P1-M39" AND NOT "DB TT Alarm"."A371_04_1", Pressure_Control_Zone_3 := "P1-M41" AND NOT "DB TT Alarm"."A371_04_2", Pressure_Control_Zone_4 := "P1-M42" AND NOT "DB TT Alarm"."A371_04_3", Pressure_Control_Zone_5 := FALSE);
|
||||||
|
|
||||||
|
// Network 2: Elevator Door Management - UpStair (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Door Control - Lifter - UpStair"(BUTTON_REQUEST := "E7.2", CLK_FAST := "M1.3", CLK_SLOW := "M1.5", DOOR_OPEN := "E7.6" OR "E7.7" OR NOT "KS165-1C", FBK_MACHINE_OFF := Eq("DB TT Motor 35"."Manage"."STATUS_VFD_ACT_Speed_Hz", 0));
|
||||||
|
|
||||||
|
// Network 3: Elevator Door Management - DownStair (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Door Control - Lifter - DownStair"(BUTTON_REQUEST := "E7.0", CLK_FAST := "M1.3", CLK_SLOW := "M1.5", DOOR_OPEN := "E7.4" OR "E7.5" OR NOT "KS165-1C", FBK_MACHINE_OFF := Eq("DB TT Motor 35"."Manage"."STATUS_VFD_ACT_Speed_Hz", 0));
|
||||||
|
|
||||||
|
// Network 4: Elevator - Right/ Left Control breaking chains (Original Language: LAD)
|
||||||
|
|
||||||
|
"Timer_Chain_Right"(IN := NOT "S1-M35", PT := S5T#1500ms); // TODO: Declarar "Timer_Chain_Right" : TON;
|
||||||
|
|
||||||
|
"Timer_Chain_Left"(IN := NOT "S2-M35", PT := S5T#1500ms); // TODO: Declarar "Timer_Chain_Left" : TON;
|
||||||
|
|
||||||
|
// Network 5: Energy Saving - Line Empty (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 5 ---
|
||||||
|
```stl
|
||||||
|
A "B1-M31"
|
||||||
|
A "B1-M32"
|
||||||
|
A "B2-M32"
|
||||||
|
A "B1-M34"
|
||||||
|
A "B2-M34"
|
||||||
|
A "B1-M35"
|
||||||
|
A "B2-M35"
|
||||||
|
A "B4-M35"
|
||||||
|
A "B5-M35"
|
||||||
|
A "B1-M36"
|
||||||
|
A "B1-M37"
|
||||||
|
A "B2-M37"
|
||||||
|
A "B1-M38"
|
||||||
|
A "B2-M38"
|
||||||
|
A "B1-M39"
|
||||||
|
A "B2-M39"
|
||||||
|
A "B1-M40"
|
||||||
|
A "B2-M40"
|
||||||
|
A "B1-M41"
|
||||||
|
A "B2-M41"
|
||||||
|
A "B1-M42"
|
||||||
|
A "B2-M42"
|
||||||
|
= "Line Empty"
|
||||||
|
```
|
||||||
|
// --- END STL Network 5 ---
|
||||||
|
|
||||||
|
// Network 6: Energy Saving (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB TTOP - Energy Saving"(DownStream_Mac_Req := "M0.1" OR ("DB Signal DownStream Machine - TL25_Q2"."IN_DIG_Signal_01" AND "M0.0"), Sensor_on_the_line := "Line Empty", UpStream_Mac_Empty := "DB TT Run"."TT_Run"."OUT_Cycle_ON" AND (("ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X00" AND "ComSV"."TL25_ReadFromSv"."FromSV"."Data From TL28"."Run") OR (NOT "ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X00" AND NOT "ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X13" AND NOT "ComSV"."TL25_ReadFromSv"."FromSV"."STW"."X14")));
|
||||||
|
|
||||||
|
// Network 7: Bottle Counter M153_154 (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Bottle Counter M153_154"(Conveyor_Running := "DB TT Motor 41"."Manage"."STATUS_VFD_Run_FWD" AND "DB TT Motor 42"."Manage"."STATUS_VFD_Run_FWD", PH_Inlet := "Count 1 M42", PH_Outlet := "Count 2 M42", Reset_Button_Allarm := "SH331-1B", Reset_Counter_Henkel := "ComSV"."TL25_WriteToSv"."FromHenkel"."STW"."di0.x"[1]);
|
||||||
|
|
||||||
|
// Network 8: Bottle Counter M37 (Original Language: LAD)
|
||||||
|
|
||||||
|
"DB Bottle Counter_M37"(Conveyor_Running := "DB TT Motor 37"."Manage"."STATUS_VFD_Run_FWD", PH_Inlet := "Count 1 M35", PH_Outlet := "Count 2 M35", Reset_Button_Allarm := "SH331-1B", Reset_Counter_Henkel := "ComSV"."TL25_WriteToSv"."FromHenkel"."STW"."di0.x"[1]);
|
||||||
|
|
||||||
|
IF "M0.1" THEN
|
||||||
|
"DB TT Alarm"."A371_03_3" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 9: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "Tag_27" > 5 THEN
|
||||||
|
"Tag_27" := 0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"Apoyo_Rechazo" := "B5-M35" OR ("M0.0" AND Eq("Tag_27", 5));
|
||||||
|
|
||||||
|
// Network 10: Ejector Bottle (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 10 ---
|
||||||
|
```stl
|
||||||
|
CALL "DB Ejector Bottle"
|
||||||
|
```
|
||||||
|
// --- END STL Network 10 ---
|
||||||
|
|
||||||
|
// Network 11: Photocell Teach (Original Language: LAD)
|
||||||
|
|
||||||
|
"Delay Photocell Teach"(IN := "DB General"."X203_0", PT := S5T#0.8s); // TODO: Declarar "Delay Photocell Teach" : TP;
|
||||||
|
|
||||||
|
"A8.0" := "Delay Photocell Teach".Q;
|
||||||
|
|
||||||
|
"DB General"."X203_1" := "Delay Photocell Teach".Q;
|
||||||
|
|
||||||
|
IF "Delay Photocell Teach".Q THEN
|
||||||
|
"DB General"."X203_0" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 12: Elevator - Guide (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 12 ---
|
||||||
|
```stl
|
||||||
|
CALL "DB Guide Lifter - Lowerator"
|
||||||
|
```
|
||||||
|
// --- END STL Network 12 ---
|
||||||
|
|
||||||
|
// Network 13: Elevator - Lube (Original Language: STL)
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 13 ---
|
||||||
|
```stl
|
||||||
|
|
||||||
|
CALL "DB lube M35"
|
||||||
|
```
|
||||||
|
// --- END STL Network 13 ---
|
||||||
|
|
||||||
|
// Network 14: Camera Ejector Bottle (Original Language: STL)
|
||||||
|
// "E38.1"
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 14 ---
|
||||||
|
```stl
|
||||||
|
CALL "DB Camera Ejector Bottle"
|
||||||
|
```
|
||||||
|
// --- END STL Network 14 ---
|
||||||
|
|
||||||
|
// Network 15: (Original Language: LAD)
|
||||||
|
|
||||||
|
// Network 15 did not produce printable SCL code.
|
||||||
|
|
||||||
|
// Network 16: Elevator - SV Reject Y1-M35 (Original Language: LAD)
|
||||||
|
|
||||||
|
"Y1-M35" := "Ejector_Tower" OR "Ejector_Camera";
|
||||||
|
|
||||||
|
// Network 17: Signal for changeover done (Original Language: LAD)
|
||||||
|
|
||||||
|
"Ap_EMD_InPsosition" := Eq("DB TTOP - Body Guide EMD"."Counter_Position", "DB TTOP - Body Guide EMD"."Position_Selection");
|
||||||
|
|
||||||
|
"Ap_HighLim" := ("DB Guide Lifter - Lowerator"."Position Selection") + ("DB Guide Lifter - Lowerator"."Range Position");
|
||||||
|
|
||||||
|
"Ap_LowLim" := ("DB Guide Lifter - Lowerator"."Position Selection") - ("DB Guide Lifter - Lowerator"."Range Position");
|
||||||
|
|
||||||
|
"Ap_LifterGuideInPositon" := "DB Guide Lifter - Lowerator"."Actual Position" >= "Ap_LowLim";
|
||||||
|
|
||||||
|
// Network 18: INTERLOCK EMD CHANGEOVER (Original Language: SCL)
|
||||||
|
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X13 := "ComSV".TL25_ReadFromSv.FromSV.STW.X06;
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X14 := "ComSV".TL25_ReadFromSv.FromSV.STW.X07;
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X15 := "ComSV".TL25_ReadFromSv.FromSV.STW.X08;
|
||||||
|
"ComSV".TL25_WriteToSv.ToSV.STW.QE1.X16 := "ComSV".TL25_ReadFromSv.FromSV.STW.X09;
|
||||||
|
|
||||||
|
END_FUNCTION
|
|
@ -1,455 +0,0 @@
|
||||||
// Block Type: FC
|
|
||||||
// Block Name (Original): FC Ttop Motor M31010
|
|
||||||
// Block Number: 327
|
|
||||||
// Original Network Languages: LAD, SCL
|
|
||||||
|
|
||||||
FUNCTION "FC_Ttop_Motor_M31010" : Void
|
|
||||||
{ S7_Optimized_Access := 'TRUE' }
|
|
||||||
VERSION : 0.1
|
|
||||||
|
|
||||||
VAR_INOUT
|
|
||||||
Motor : STRUCT
|
|
||||||
RCP_Speed_Fix_01 : Int;
|
|
||||||
RCP_Speed_Fix_02 : Int;
|
|
||||||
RCP_Speed_Fix_03 : Int;
|
|
||||||
RCP_Speed_Fix_04 : Int;
|
|
||||||
RCP_Speed_Fix_05 : Int;
|
|
||||||
RCP_Speed_Sync_01 : Int;
|
|
||||||
RCP_Speed_Sync_02 : Int;
|
|
||||||
RCP_Speed_Sync_03 : Int;
|
|
||||||
RCP_Speed_Sync_04 : Int;
|
|
||||||
RCP_Speed_Sync_05 : Int;
|
|
||||||
RCP_Timer_01 : Int;
|
|
||||||
RCP_Timer_02 : Int;
|
|
||||||
RCP_Timer_03 : Int;
|
|
||||||
RCP_Timer_04 : Int;
|
|
||||||
RCP_Timer_05 : Int;
|
|
||||||
RCP_Speed_Fix_01_mBar : Int;
|
|
||||||
RCP_Speed_Fix_02_mBar : Int;
|
|
||||||
RCP_Speed_Fix_03_mBar : Int;
|
|
||||||
RCP_Speed_Fix_04_mBar : Int;
|
|
||||||
RCP_Speed_Fix_05_mBar : Int;
|
|
||||||
RCP_ACC_Ramp : Int;
|
|
||||||
RCP_DEC_Ramp : Int;
|
|
||||||
RCP_W044 : Int;
|
|
||||||
RCP_W046 : Int;
|
|
||||||
RCP_W048 : Int;
|
|
||||||
CFG_VFD : Bool;
|
|
||||||
CFG_DP : Bool;
|
|
||||||
CFG_Analog_Speed : Bool;
|
|
||||||
CFG_EN_BWD : Bool;
|
|
||||||
CFG_Reverse : Bool;
|
|
||||||
CFG_Motor_N_Sel : Bool;
|
|
||||||
CFG_PN : Bool;
|
|
||||||
CFG_X050_7 : Bool;
|
|
||||||
CFG_TH_CTR_Single : Bool;
|
|
||||||
CFG_SW_CTR_Single : Bool;
|
|
||||||
CFG_TRIP_CTR_Single : Bool;
|
|
||||||
CFG_Speed_User : Bool;
|
|
||||||
CFG_mBar : Bool;
|
|
||||||
CFG_SW_CTR_OnOff : Bool;
|
|
||||||
CFG_Plug_CTR_Single : Bool;
|
|
||||||
CFG_X051_7 : Bool;
|
|
||||||
CFG_Min_Speed_Hz : Int;
|
|
||||||
CFG_Max_Speed_Hz : Int;
|
|
||||||
CFG_mBar_Type : Byte;
|
|
||||||
CFG_B57 : Byte;
|
|
||||||
CFG_Max_mBar : Int;
|
|
||||||
CFG_EOLO_Zone : Bool;
|
|
||||||
CFG_TableTop_Zone : Bool;
|
|
||||||
CFG_Pack_Zone : Bool;
|
|
||||||
CFG_VIS_Sp_User_Step200 : Bool;
|
|
||||||
CFG_X060_4 : Bool;
|
|
||||||
CFG_X060_5 : Bool;
|
|
||||||
CFG_X060_6 : Bool;
|
|
||||||
CFG_X060_7 : Bool;
|
|
||||||
CFG_MPrew : Int;
|
|
||||||
CFG_MNext : Int;
|
|
||||||
CFG_DBExternal1 : Int;
|
|
||||||
CFG_DBExternal2 : Int;
|
|
||||||
CFG_Vis_Fix_00 : Bool;
|
|
||||||
CFG_VIS_Fix_01 : Bool;
|
|
||||||
CFG_VIS_Fix_02 : Bool;
|
|
||||||
CFG_VIS_Fix_03 : Bool;
|
|
||||||
CFG_VIS_Fix_04 : Bool;
|
|
||||||
CFG_VIS_Fix_05 : Bool;
|
|
||||||
CFG_VIS_Fix_06 : Bool;
|
|
||||||
CFG_VIS_Fix_07 : Bool;
|
|
||||||
CFG_VIS_Sync_00 : Bool;
|
|
||||||
CFG_VIS_Sync_01 : Bool;
|
|
||||||
CFG_VIS_Sync_02 : Bool;
|
|
||||||
CFG_VIS_Sync_03 : Bool;
|
|
||||||
CFG_VIS_Sync_04 : Bool;
|
|
||||||
CFG_VIS_Sync_05 : Bool;
|
|
||||||
CFG_VIS_Sync_06 : Bool;
|
|
||||||
CFG_VIS_Sync_07 : Bool;
|
|
||||||
CFG_VIS_Timer_00 : Bool;
|
|
||||||
CFG_VIS_Timer_01 : Bool;
|
|
||||||
CFG_VIS_Timer_02 : Bool;
|
|
||||||
CFG_VIS_Timer_03 : Bool;
|
|
||||||
CFG_VIS_Timer_04 : Bool;
|
|
||||||
CFG_VIS_Timer_05 : Bool;
|
|
||||||
CFG_VIS_Timer_06 : Bool;
|
|
||||||
CFG_VIS_Timer_07 : Bool;
|
|
||||||
CFG_VIS_SA : Bool;
|
|
||||||
CFG_VIS_SB : Bool;
|
|
||||||
CFG_VIS_SC : Bool;
|
|
||||||
CFG_VIS_SD : Bool;
|
|
||||||
CFG_VIS_BA : Bool;
|
|
||||||
CFG_VIS_BB : Bool;
|
|
||||||
CFG_VIS_EXTA : Bool;
|
|
||||||
CFG_VIS_EXTB : Bool;
|
|
||||||
CFG_VIS_SW : Bool;
|
|
||||||
CFG_VIS_TH : Bool;
|
|
||||||
CFG_VIS_TRIP : Bool;
|
|
||||||
CFG_VIS_PAW : Bool;
|
|
||||||
CFG_VIS_RUN_FWD : Bool;
|
|
||||||
CFG_VIS_RUN_BWD : Bool;
|
|
||||||
CFG_VIS_Kspeed : Bool;
|
|
||||||
CFG_VIS_PLUG : Bool;
|
|
||||||
CFG_VIS_PB_Auto : Bool;
|
|
||||||
CFG_VIS_PB_Man : Bool;
|
|
||||||
CFG_VIS_PB_Jog : Bool;
|
|
||||||
CFG_VIS_PB_Stop : Bool;
|
|
||||||
CFG_VIS_PB_Reverse : Bool;
|
|
||||||
CFG_VIS_PB_sp_05 : Bool;
|
|
||||||
CFG_VIS_PB_sp_06 : Bool;
|
|
||||||
CFG_VIS_ManSpeed : Bool;
|
|
||||||
CFG_VIS_ACT_Torque : Bool;
|
|
||||||
CFG_VIS_ACC_Ramp : Bool;
|
|
||||||
CFG_VIS_DEC_Ramp : Bool;
|
|
||||||
CFG_VIS_X76_3 : Bool;
|
|
||||||
CFG_VIS_X76_4 : Bool;
|
|
||||||
CFG_VIS_X76_5 : Bool;
|
|
||||||
CFG_VIS_X76_6 : Bool;
|
|
||||||
CFG_VIS_X76 : Bool;
|
|
||||||
CFG_B77 : Byte;
|
|
||||||
CFG_W078 : Int;
|
|
||||||
CFG_Add_Signal_SA : UInt;
|
|
||||||
CFG_Add_Signal_SB : UInt;
|
|
||||||
CFG_Add_Signal_SC : UInt;
|
|
||||||
CFG_Add_Signal_SD : UInt;
|
|
||||||
CFG_Add_Signal_BA : UInt;
|
|
||||||
CFG_Add_Signal_BB : UInt;
|
|
||||||
CFG_Add_Signal_EXTA : UInt;
|
|
||||||
CFG_Add_Signal_EXTB : UInt;
|
|
||||||
CFG_Add_Signal_SW : UInt;
|
|
||||||
CFG_Add_Signal_TH : UInt;
|
|
||||||
CFG_Add_Signal_TRIP : UInt;
|
|
||||||
CFG_Add_Signal_PAW : Int;
|
|
||||||
CFG_Add_Signal_RUN_FWD : UInt;
|
|
||||||
CFG_Add_Signal_RUN_BWD : UInt;
|
|
||||||
CFG_Add_Signal_mBar : Int;
|
|
||||||
CFG_Add_Signal_PLUG : Int;
|
|
||||||
CFG_Add_Signal_SP02 : Int;
|
|
||||||
CFG_DB_Machine : Int;
|
|
||||||
CFG_DB_NextMotor : Int;
|
|
||||||
CFG_W118 : Int;
|
|
||||||
CFG_Stop_Empty : Bool;
|
|
||||||
CFG_Stop_Full : Bool;
|
|
||||||
CFG_Stop_STBY : Bool;
|
|
||||||
CFG_Pressurization : Bool;
|
|
||||||
CFG_EOLO_Press_Speed : Int;
|
|
||||||
Spare_124 : Array[124..145] of Byte;
|
|
||||||
CFG_Motor_N : DInt;
|
|
||||||
CFG_Phylosopy_N : Int;
|
|
||||||
CFG_Motor_HW_IO : "HW_IO";
|
|
||||||
CFG_Node_N : Int;
|
|
||||||
CFG_Inverter_Type : Int;
|
|
||||||
CFG_W158 : Int;
|
|
||||||
CFG_Kspeed_User50Hz : Int;
|
|
||||||
CFG_Min_Speed_User : Int;
|
|
||||||
CFG_Max_Speed_User : Int;
|
|
||||||
CFG_W166 : Int;
|
|
||||||
CFG_W168 : Int;
|
|
||||||
CFG_EN_mBar_FCT : Bool;
|
|
||||||
CFG_EN_mBar_FilterALM : Bool;
|
|
||||||
CFG_Isteresi_mBar : Int;
|
|
||||||
CFG_Gain_Mbar : Int;
|
|
||||||
CFG_Max_Speed_FilterALM : Int;
|
|
||||||
CFG_W178 : Int;
|
|
||||||
CFG_T_Gain : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
CFG_T_FilterALM : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
IN_PB_Start : Bool;
|
|
||||||
IN_PB_Stop : Bool;
|
|
||||||
IN_PB_Reset : Bool;
|
|
||||||
IN_PB_Silence : Bool;
|
|
||||||
IN_X200_4 : Bool;
|
|
||||||
IN_X200_5 : Bool;
|
|
||||||
IN_X200_6 : Bool;
|
|
||||||
IN_X200_7 : Bool;
|
|
||||||
IN_KG_PowerON : Bool;
|
|
||||||
IN_SW_ManAuto : Bool;
|
|
||||||
IN_Cycle_ON : Bool;
|
|
||||||
IN_X201_3 : Bool;
|
|
||||||
IN_X201_4 : Bool;
|
|
||||||
IN_X201_5 : Bool;
|
|
||||||
IN_X201_6 : Bool;
|
|
||||||
IN_X201_7 : Bool;
|
|
||||||
IN_SW_HMI_Auto : Bool;
|
|
||||||
IN_SW_HMI_Man : Bool;
|
|
||||||
IN_SW_HMI_Jog : Bool;
|
|
||||||
IN_SW_HMI_Stop : Bool;
|
|
||||||
IN_SW_HMI_Reverse : Bool;
|
|
||||||
IN_SW_HMI_sp_05 : Bool;
|
|
||||||
IN_SW_HMI_sp_06 : Bool;
|
|
||||||
IN_SW_HMI_ManSpeed : Bool;
|
|
||||||
IN_SW_HMI_sp_08 : Bool;
|
|
||||||
IN_SW_HMI_VVFix1 : Bool;
|
|
||||||
IN_SW_HMI_VVFix2 : Bool;
|
|
||||||
IN_SW_HMI_VVFix3 : Bool;
|
|
||||||
IN_SW_HMI_VVFix4 : Bool;
|
|
||||||
IN_SW_HMI_VVFix5 : Bool;
|
|
||||||
IN_SW_HMI_sp_14 : Bool;
|
|
||||||
IN_SW_HMI_sp_15 : Bool;
|
|
||||||
IN_HMI_ManSpeed : Int;
|
|
||||||
IN_Signal_SA : Bool;
|
|
||||||
IN_Signal_SB : Bool;
|
|
||||||
IN_Signal_SC : Bool;
|
|
||||||
IN_Signal_SD : Bool;
|
|
||||||
IN_Signal_BA : Bool;
|
|
||||||
IN_Signal_BB : Bool;
|
|
||||||
IN_Signal_EXTA : Bool;
|
|
||||||
IN_Signal_EXTB : Bool;
|
|
||||||
IN_Signal_SW : Bool;
|
|
||||||
IN_Signal_TH : Bool;
|
|
||||||
IN_Signal_TRIP : Bool;
|
|
||||||
IN_Signal_RUN_FWD : Bool;
|
|
||||||
IN_Signal_RUN_BWD : Bool;
|
|
||||||
IN_Signal_sp_05 : Bool;
|
|
||||||
IN_Signal_sp_06 : Bool;
|
|
||||||
IN_Signal_PLUG : Bool;
|
|
||||||
IN_Signal_sp_08 : Int;
|
|
||||||
IN_Signal_PEW_mBar : Int;
|
|
||||||
IN_Signal_mBar : Int;
|
|
||||||
IN_Motor_DI : "Struct";
|
|
||||||
IN_W216 : Int;
|
|
||||||
IN_W218 : Int;
|
|
||||||
IN_Line_Empty : Bool;
|
|
||||||
IN_Line_Full : Bool;
|
|
||||||
IN_Line_StandBy : Bool;
|
|
||||||
Spare_222 : Array[222..249] of Byte;
|
|
||||||
OUT_VFD_Run_FWD : Bool;
|
|
||||||
OUT_VFD_Run_BWD : Bool;
|
|
||||||
OUT_VFD_Reverse : Bool;
|
|
||||||
OUT_VFD_Qstop : Bool;
|
|
||||||
OUT_VFD_Reset : Bool;
|
|
||||||
OUT_X250_5 : Bool;
|
|
||||||
OUT_X250_6 : Bool;
|
|
||||||
OUT_EnergySavingON : Bool;
|
|
||||||
OUT_VFD_REQ_Speed_Hz : Int;
|
|
||||||
OUT_VFD_REQ_Speed_User : Int;
|
|
||||||
OUT_VFD_ACT_Sync_Speed : Int;
|
|
||||||
OUT_VFD_REQ_Speed_mBar : Int;
|
|
||||||
OUT_Motor_DO : "Struct";
|
|
||||||
OUT_W262 : Int;
|
|
||||||
OUT_W264 : Int;
|
|
||||||
OUT_W266 : Int;
|
|
||||||
OUT_W268 : Int;
|
|
||||||
STATUS_VFD_Run_FWD : Bool;
|
|
||||||
STATUS_VFD_Run_BWD : Bool;
|
|
||||||
STATUS_VFD_Trip : Bool;
|
|
||||||
STATUS_VFD_Warning : Bool;
|
|
||||||
STATUS_Ready : Bool;
|
|
||||||
STATUS_VFD_Ready : Bool;
|
|
||||||
STATUS_VFD_Coasting : Bool;
|
|
||||||
STATUS_X270_7 : Bool;
|
|
||||||
STATUS_VFD_ACT_Speed_Hz : Int;
|
|
||||||
STATUS_VFD_ACT_Speed_Use : Int;
|
|
||||||
STATUS_VFD_ACT_Torque : Int;
|
|
||||||
STATUS_MainFault_MovigearADV : Byte;
|
|
||||||
STATUS_Subfault_MovigearADV : Byte;
|
|
||||||
STATUS_W280 : Int;
|
|
||||||
STATUS_W282 : Int;
|
|
||||||
STATUS_PWR_OFF : Bool;
|
|
||||||
STATUS_CYCLE_OFF : Bool;
|
|
||||||
STATUS_ALARM : Bool;
|
|
||||||
STATUS_AUTO : Bool;
|
|
||||||
STATUS_MAN : Bool;
|
|
||||||
STATUS_JOG : Bool;
|
|
||||||
STATUS_STOP : Bool;
|
|
||||||
STATUS_X284_7 : Bool;
|
|
||||||
STATUS_X285_0 : Bool;
|
|
||||||
STATUS_X285_1 : Bool;
|
|
||||||
STATUS_X285_2 : Bool;
|
|
||||||
STATUS_X285_3 : Bool;
|
|
||||||
STATUS_X285_4 : Bool;
|
|
||||||
STATUS_X285_5 : Bool;
|
|
||||||
STATUS_X285_6 : Bool;
|
|
||||||
STATUS_X285_7 : Bool;
|
|
||||||
STATUS_NOTRUN : Bool;
|
|
||||||
STATUS_RUN : Bool;
|
|
||||||
STATUS_X286_2 : Bool;
|
|
||||||
STATUS_X286_3 : Bool;
|
|
||||||
STATUS_X286_4 : Bool;
|
|
||||||
STATUS_X286_5 : Bool;
|
|
||||||
STATUS_X286_6 : Bool;
|
|
||||||
STATUS_X286_7 : Bool;
|
|
||||||
Spare_288 : Array[288..289] of Byte;
|
|
||||||
Alarm_09 : Bool;
|
|
||||||
Alarm_10 : Bool;
|
|
||||||
Alarm_11 : Bool;
|
|
||||||
Alarm_12 : Bool;
|
|
||||||
Alarm_13 : Bool;
|
|
||||||
Alarm_14 : Bool;
|
|
||||||
Alarm_15 : Bool;
|
|
||||||
Alarm_16 : Bool;
|
|
||||||
Alarm_01 : Bool;
|
|
||||||
Alarm_02 : Bool;
|
|
||||||
Alarm_03 : Bool;
|
|
||||||
Alarm_04 : Bool;
|
|
||||||
Alarm_05 : Bool;
|
|
||||||
Alarm_06 : Bool;
|
|
||||||
Alarm_07 : Bool;
|
|
||||||
Alarm_08 : Bool;
|
|
||||||
Spare_292 : Array[292..299] of Byte;
|
|
||||||
M_Power_ON : Bool;
|
|
||||||
M_Cycle_ON_AUTO : Bool;
|
|
||||||
M_Cycle_ON_MAN : Bool;
|
|
||||||
M_W302 : Int;
|
|
||||||
M_W304 : Int;
|
|
||||||
M_W306 : Int;
|
|
||||||
M_W308 : Int;
|
|
||||||
M_Delay_Cycle_ON_Auto : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
Spare_320 : Array[320..349] of Byte;
|
|
||||||
REQ_EN_Run : Bool;
|
|
||||||
REQ_Start_FWD : Bool;
|
|
||||||
REQ_Start_BWD : Bool;
|
|
||||||
REQ_QStop : Bool;
|
|
||||||
REQ_X350_4 : Bool;
|
|
||||||
REQ_X350_5 : Bool;
|
|
||||||
REQ_X350_6 : Bool;
|
|
||||||
REQ_X350_7 : Bool;
|
|
||||||
REQ_X351_0 : Bool;
|
|
||||||
REQ_X351_1 : Bool;
|
|
||||||
REQ_X351_2 : Bool;
|
|
||||||
REQ_X351_3 : Bool;
|
|
||||||
REQ_X351_4 : Bool;
|
|
||||||
REQ_X351_5 : Bool;
|
|
||||||
REQ_X351_6 : Bool;
|
|
||||||
REQ_X351_7 : Bool;
|
|
||||||
REQ_W352 : Int;
|
|
||||||
REQ_Master_Speed_Sync : Int;
|
|
||||||
REQ_W356 : Int;
|
|
||||||
REQ_Speed_Fix_00_NU : Bool;
|
|
||||||
REQ_Speed_Fix_01 : Bool;
|
|
||||||
REQ_Speed_Fix_02 : Bool;
|
|
||||||
REQ_Speed_Fix_03 : Bool;
|
|
||||||
REQ_Speed_Fix_04 : Bool;
|
|
||||||
REQ_Speed_Fix_05 : Bool;
|
|
||||||
REQ_Speed_Fix_06_NU : Bool;
|
|
||||||
REQ_Speed_Fix_07_NU : Bool;
|
|
||||||
REQ_Speed_Sync_00_NU : Bool;
|
|
||||||
REQ_Speed_Sync_01 : Bool;
|
|
||||||
REQ_Speed_Sync_02 : Bool;
|
|
||||||
REQ_Speed_Sync_03 : Bool;
|
|
||||||
REQ_Speed_Sync_04 : Bool;
|
|
||||||
REQ_Speed_Sync_05 : Bool;
|
|
||||||
REQ_Speed_Sync_06_NU : Bool;
|
|
||||||
REQ_Speed_Sync_07_NU : Bool;
|
|
||||||
REQ_T01 : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
REQ_T02 : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
REQ_T03 : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
REQ_T04 : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
REQ_T05 : STRUCT
|
|
||||||
S : Bool;
|
|
||||||
Q : Bool;
|
|
||||||
TW : Int;
|
|
||||||
ST : Int;
|
|
||||||
ACT : Int;
|
|
||||||
W008 : Int;
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
END_STRUCT;
|
|
||||||
|
|
||||||
END_VAR
|
|
||||||
|
|
||||||
VAR_TEMP
|
|
||||||
RetVal : Int;
|
|
||||||
MotorNumber : Int;
|
|
||||||
DBNumber : Int;
|
|
||||||
END_VAR
|
|
||||||
|
|
||||||
BEGIN
|
|
||||||
|
|
||||||
// Network 1: INIT Configuration (Original Language: SCL)
|
|
||||||
|
|
||||||
// SCL extraction failed: StructuredText node not found.
|
|
||||||
|
|
||||||
// Network 2: (Original Language: LAD)
|
|
||||||
|
|
||||||
// Network 2 has no logic elements.
|
|
||||||
|
|
||||||
// Network 3: EN run (Original Language: LAD)
|
|
||||||
|
|
||||||
"Motor"."REQ_EN_Run" := "M0.1";
|
|
||||||
|
|
||||||
// Network 4: REQ Auto RUN (Original Language: LAD)
|
|
||||||
|
|
||||||
"Motor"."REQ_Start_FWD" := TRUE;
|
|
||||||
|
|
||||||
// Network 5: Request Speed Fix 01 (Original Language: LAD)
|
|
||||||
|
|
||||||
"Motor"."REQ_Speed_Fix_01" := "M0.1";
|
|
||||||
|
|
||||||
// Network 6: INIT Configuration (Original Language: SCL)
|
|
||||||
|
|
||||||
// SCL extraction failed: StructuredText node not found.
|
|
||||||
|
|
||||||
END_FUNCTION
|
|
Binary file not shown.
|
@ -6,6 +6,7 @@ import re
|
||||||
# Importar desde las utilidades del parser
|
# Importar desde las utilidades del parser
|
||||||
from .parser_utils import ns, get_multilingual_text
|
from .parser_utils import ns, get_multilingual_text
|
||||||
|
|
||||||
|
|
||||||
def reconstruct_scl_from_tokens(st_node):
|
def reconstruct_scl_from_tokens(st_node):
|
||||||
"""
|
"""
|
||||||
Reconstruye SCL desde <StructuredText>, mejorando el manejo de
|
Reconstruye SCL desde <StructuredText>, mejorando el manejo de
|
||||||
|
@ -15,10 +16,21 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
return "// Error: StructuredText node not found.\n"
|
return "// Error: StructuredText node not found.\n"
|
||||||
|
|
||||||
scl_parts = []
|
scl_parts = []
|
||||||
# Usar st:* para obtener todos los elementos hijos dentro del namespace st
|
# Usar st:* para obtener todos los elementos hijos, primero con namespace, luego sin namespace
|
||||||
children = st_node.xpath("./st:*", namespaces=ns)
|
children = st_node.xpath("./st:*", namespaces=ns)
|
||||||
|
if not children:
|
||||||
|
# Si no se encuentran con namespace, buscar sin namespace
|
||||||
|
children = st_node.xpath("./*")
|
||||||
|
|
||||||
|
# Set to track elements that have been processed as part of array access
|
||||||
|
processed_elements = set()
|
||||||
|
|
||||||
for elem in children:
|
for elem in children:
|
||||||
|
# Skip elements that have already been processed
|
||||||
|
elem_id = elem.get("UId")
|
||||||
|
if elem_id and elem_id in processed_elements:
|
||||||
|
continue
|
||||||
|
|
||||||
tag = etree.QName(elem.tag).localname
|
tag = etree.QName(elem.tag).localname
|
||||||
|
|
||||||
if tag == "Token":
|
if tag == "Token":
|
||||||
|
@ -29,7 +41,7 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
if not scl_parts or not scl_parts[-1].endswith(" "):
|
if not scl_parts or not scl_parts[-1].endswith(" "):
|
||||||
scl_parts.append(" " * num_spaces)
|
scl_parts.append(" " * num_spaces)
|
||||||
elif num_spaces > 1:
|
elif num_spaces > 1:
|
||||||
scl_parts.append(" " * (num_spaces -1))
|
scl_parts.append(" " * (num_spaces - 1))
|
||||||
|
|
||||||
elif tag == "NewLine":
|
elif tag == "NewLine":
|
||||||
# Quitar espacios finales antes del salto de línea
|
# Quitar espacios finales antes del salto de línea
|
||||||
|
@ -40,46 +52,208 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
scope = elem.get("Scope")
|
scope = elem.get("Scope")
|
||||||
access_str = f"/*_ERR_Scope_{scope}_*/" # Placeholder
|
access_str = f"/*_ERR_Scope_{scope}_*/" # Placeholder
|
||||||
|
|
||||||
|
# --- Constantes Locales (estructura diferente) ---
|
||||||
|
if scope == "LocalConstant":
|
||||||
|
# Las constantes locales tienen estructura <Constant Name="..." /> directamente
|
||||||
|
constant_elem = elem.xpath("./st:Constant", namespaces=ns)
|
||||||
|
if not constant_elem:
|
||||||
|
constant_elem = elem.xpath("./Constant")
|
||||||
|
|
||||||
|
if constant_elem:
|
||||||
|
const_name = constant_elem[0].get("Name", "_ERR_CONST_NAME_")
|
||||||
|
access_str = f"#{const_name}" # Las constantes locales van con #
|
||||||
|
else:
|
||||||
|
access_str = f"/*_ERR_NO_SYMBOL_IN_{scope}_*/"
|
||||||
|
|
||||||
# --- Variables ---
|
# --- Variables ---
|
||||||
if scope in [
|
elif scope in [
|
||||||
"GlobalVariable", "LocalVariable", "TempVariable", "InOutVariable",
|
"GlobalVariable",
|
||||||
"InputVariable", "OutputVariable", "ConstantVariable",
|
"LocalVariable",
|
||||||
"GlobalConstant", "LocalConstant" # Añadir constantes simbólicas
|
"TempVariable",
|
||||||
|
"InOutVariable",
|
||||||
|
"InputVariable",
|
||||||
|
"OutputVariable",
|
||||||
|
"ConstantVariable",
|
||||||
|
"GlobalConstant",
|
||||||
]:
|
]:
|
||||||
|
# Buscar Symbol tanto con namespace st: como sin namespace
|
||||||
symbol_elem = elem.xpath("./st:Symbol", namespaces=ns)
|
symbol_elem = elem.xpath("./st:Symbol", namespaces=ns)
|
||||||
|
if not symbol_elem:
|
||||||
|
symbol_elem = elem.xpath("./Symbol")
|
||||||
|
|
||||||
if symbol_elem:
|
if symbol_elem:
|
||||||
|
# Buscar Components tanto con namespace st: como sin namespace
|
||||||
components = symbol_elem[0].xpath("./st:Component", namespaces=ns)
|
components = symbol_elem[0].xpath("./st:Component", namespaces=ns)
|
||||||
|
if not components:
|
||||||
|
components = symbol_elem[0].xpath("./Component")
|
||||||
symbol_text_parts = []
|
symbol_text_parts = []
|
||||||
for i, comp in enumerate(components):
|
for i, comp in enumerate(components):
|
||||||
name = comp.get("Name", "_ERR_COMP_")
|
name = comp.get("Name", "_ERR_COMP_")
|
||||||
if i > 0: symbol_text_parts.append(".")
|
if i > 0:
|
||||||
|
symbol_text_parts.append(".")
|
||||||
|
|
||||||
# Check for HasQuotes attribute (adjust namespace if needed)
|
# Check for HasQuotes attribute (adjust namespace if needed)
|
||||||
# El atributo está en el Component o en el Access padre? Probar ambos
|
# El atributo está en el Component o en el Access padre? Probar ambos
|
||||||
has_quotes_comp = comp.get("HasQuotes", "false").lower() == "true" # Check directly on Component
|
has_quotes_comp = (
|
||||||
|
comp.get("HasQuotes", "false").lower() == "true"
|
||||||
|
) # Check directly on Component
|
||||||
has_quotes_access = False
|
has_quotes_access = False
|
||||||
access_parent = comp.xpath("ancestor::st:Access[1]", namespaces=ns) # Get immediate Access parent
|
|
||||||
|
# Buscar BooleanAttribute tanto con namespace como sin namespace
|
||||||
|
access_parent = comp.xpath(
|
||||||
|
"ancestor::st:Access[1]", namespaces=ns
|
||||||
|
) # Get immediate Access parent with namespace
|
||||||
|
if not access_parent:
|
||||||
|
access_parent = comp.xpath(
|
||||||
|
"ancestor::Access[1]"
|
||||||
|
) # Get immediate Access parent without namespace
|
||||||
|
|
||||||
if access_parent:
|
if access_parent:
|
||||||
has_quotes_attr = access_parent[0].xpath("./st:BooleanAttribute[@Name='HasQuotes']/text()", namespaces=ns)
|
has_quotes_attr = access_parent[0].xpath(
|
||||||
has_quotes_access = has_quotes_attr and has_quotes_attr[0].lower() == 'true'
|
"./st:BooleanAttribute[@Name='HasQuotes']/text()",
|
||||||
|
namespaces=ns,
|
||||||
|
)
|
||||||
|
if not has_quotes_attr:
|
||||||
|
has_quotes_attr = access_parent[0].xpath(
|
||||||
|
"./BooleanAttribute[@Name='HasQuotes']/text()"
|
||||||
|
)
|
||||||
|
has_quotes_access = (
|
||||||
|
has_quotes_attr and has_quotes_attr[0].lower() == "true"
|
||||||
|
)
|
||||||
|
|
||||||
has_quotes = has_quotes_comp or has_quotes_access
|
has_quotes = has_quotes_comp or has_quotes_access
|
||||||
is_temp = name.startswith("#")
|
is_temp = name.startswith("#")
|
||||||
|
|
||||||
# Apply quotes based on HasQuotes or if it's the first component and not temp
|
# Apply quotes based on HasQuotes or if it's the first component and not temp
|
||||||
if has_quotes or (i == 0 and not is_temp and '"' not in name): # Avoid double quotes
|
if has_quotes or (
|
||||||
|
i == 0 and not is_temp and '"' not in name
|
||||||
|
): # Avoid double quotes
|
||||||
symbol_text_parts.append(f'"{name}"')
|
symbol_text_parts.append(f'"{name}"')
|
||||||
else:
|
else:
|
||||||
symbol_text_parts.append(name)
|
symbol_text_parts.append(name)
|
||||||
|
|
||||||
# --- Array Index Access ---
|
# --- Array Index Access ---
|
||||||
index_access_nodes = comp.xpath("./st:Access", namespaces=ns)
|
# Verificar si este componente tiene hijos que indican acceso de array
|
||||||
|
# Buscar estructura: <Token Text="["/> <Access.../> <Token Text="]"/>
|
||||||
|
children = comp.xpath("./*") # Todos los hijos directos
|
||||||
|
|
||||||
|
if len(children) >= 3:
|
||||||
|
# Verificar patrón: primer hijo es Token "[", último es Token "]"
|
||||||
|
first_child = children[0]
|
||||||
|
last_child = children[-1]
|
||||||
|
first_is_open_bracket = (
|
||||||
|
etree.QName(first_child.tag).localname == "Token"
|
||||||
|
and first_child.get("Text") == "["
|
||||||
|
)
|
||||||
|
last_is_close_bracket = (
|
||||||
|
etree.QName(last_child.tag).localname == "Token"
|
||||||
|
and last_child.get("Text") == "]"
|
||||||
|
)
|
||||||
|
|
||||||
|
if first_is_open_bracket and last_is_close_bracket:
|
||||||
|
# Hay acceso de array - procesar los elementos entre los corchetes
|
||||||
|
indices_parts = []
|
||||||
|
|
||||||
|
# Mark the bracket tokens and middle elements as processed
|
||||||
|
first_uid = first_child.get("UId")
|
||||||
|
last_uid = last_child.get("UId")
|
||||||
|
if first_uid:
|
||||||
|
processed_elements.add(first_uid)
|
||||||
|
if last_uid:
|
||||||
|
processed_elements.add(last_uid)
|
||||||
|
|
||||||
|
for middle_child in children[
|
||||||
|
1:-1
|
||||||
|
]: # Todo excepto primer y último hijo
|
||||||
|
middle_uid = middle_child.get("UId")
|
||||||
|
if middle_uid:
|
||||||
|
processed_elements.add(middle_uid)
|
||||||
|
|
||||||
|
child_tag = etree.QName(middle_child.tag).localname
|
||||||
|
if child_tag == "Access":
|
||||||
|
# Procesar el Access para obtener el índice
|
||||||
|
scope = middle_child.get("Scope")
|
||||||
|
if scope == "LiteralConstant":
|
||||||
|
# Buscar el valor de la constante - tanto con namespace como sin namespace
|
||||||
|
constant_elem = middle_child.xpath(
|
||||||
|
"./st:Constant", namespaces=ns
|
||||||
|
)
|
||||||
|
if not constant_elem:
|
||||||
|
constant_elem = middle_child.xpath(
|
||||||
|
"./Constant"
|
||||||
|
)
|
||||||
|
|
||||||
|
if constant_elem:
|
||||||
|
# Buscar ConstantValue tanto con namespace como sin namespace
|
||||||
|
val_nodes = constant_elem[0].xpath(
|
||||||
|
"./st:ConstantValue", namespaces=ns
|
||||||
|
)
|
||||||
|
if not val_nodes:
|
||||||
|
val_nodes = constant_elem[0].xpath(
|
||||||
|
"./ConstantValue"
|
||||||
|
)
|
||||||
|
|
||||||
|
if val_nodes and val_nodes[0].text:
|
||||||
|
indices_parts.append(
|
||||||
|
val_nodes[0].text.strip()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Para otros tipos de acceso, usar la función recursiva
|
||||||
|
idx_result = reconstruct_scl_from_tokens(
|
||||||
|
middle_child
|
||||||
|
)
|
||||||
|
if idx_result and idx_result.strip():
|
||||||
|
indices_parts.append(idx_result.strip())
|
||||||
|
elif child_tag == "Token":
|
||||||
|
# Token de separación (como ",")
|
||||||
|
token_text = middle_child.get("Text", "")
|
||||||
|
if token_text.strip():
|
||||||
|
indices_parts.append(token_text)
|
||||||
|
|
||||||
|
if indices_parts:
|
||||||
|
symbol_text_parts.append(
|
||||||
|
f"[{','.join(indices_parts)}]"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# No es acceso de array, buscar Access anidados de la forma tradicional
|
||||||
|
index_access_nodes = comp.xpath(
|
||||||
|
"./st:Access", namespaces=ns
|
||||||
|
)
|
||||||
|
if not index_access_nodes:
|
||||||
|
index_access_nodes = comp.xpath("./Access")
|
||||||
|
|
||||||
if index_access_nodes:
|
if index_access_nodes:
|
||||||
# Llamada recursiva para cada índice
|
indices_text = [
|
||||||
indices_text = [reconstruct_scl_from_tokens(idx_node) for idx_node in index_access_nodes]
|
reconstruct_scl_from_tokens(idx_node)
|
||||||
# Limpiar saltos de línea dentro de los corchetes
|
for idx_node in index_access_nodes
|
||||||
indices_cleaned = [idx.replace('\n', '').strip() for idx in indices_text]
|
]
|
||||||
symbol_text_parts.append(f"[{','.join(indices_cleaned)}]")
|
indices_cleaned = [
|
||||||
|
idx.replace("\n", "").strip()
|
||||||
|
for idx in indices_text
|
||||||
|
]
|
||||||
|
symbol_text_parts.append(
|
||||||
|
f"[{','.join(indices_cleaned)}]"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Menos de 3 hijos, usar búsqueda tradicional de Access
|
||||||
|
index_access_nodes = comp.xpath(
|
||||||
|
"./st:Access", namespaces=ns
|
||||||
|
)
|
||||||
|
if not index_access_nodes:
|
||||||
|
index_access_nodes = comp.xpath("./Access")
|
||||||
|
|
||||||
|
if index_access_nodes:
|
||||||
|
indices_text = [
|
||||||
|
reconstruct_scl_from_tokens(idx_node)
|
||||||
|
for idx_node in index_access_nodes
|
||||||
|
]
|
||||||
|
indices_cleaned = [
|
||||||
|
idx.replace("\n", "").strip()
|
||||||
|
for idx in indices_text
|
||||||
|
]
|
||||||
|
symbol_text_parts.append(
|
||||||
|
f"[{','.join(indices_cleaned)}]"
|
||||||
|
)
|
||||||
|
|
||||||
access_str = "".join(symbol_text_parts)
|
access_str = "".join(symbol_text_parts)
|
||||||
else:
|
else:
|
||||||
|
@ -87,41 +261,145 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
|
|
||||||
# --- Constantes Literales ---
|
# --- Constantes Literales ---
|
||||||
elif scope == "LiteralConstant":
|
elif scope == "LiteralConstant":
|
||||||
|
# Buscar nodos Constant tanto con namespace st: como sin namespace
|
||||||
constant_elem = elem.xpath("./st:Constant", namespaces=ns)
|
constant_elem = elem.xpath("./st:Constant", namespaces=ns)
|
||||||
|
if not constant_elem:
|
||||||
|
# Si no se encuentran con namespace, buscar sin namespace
|
||||||
|
constant_elem = elem.xpath("./Constant")
|
||||||
|
|
||||||
if constant_elem:
|
if constant_elem:
|
||||||
val_elem = constant_elem[0].xpath("./st:ConstantValue/text()", namespaces=ns)
|
# Buscar ConstantValue tanto con namespace como sin namespace
|
||||||
type_elem = constant_elem[0].xpath("./st:ConstantType/text()", namespaces=ns)
|
val_elem = constant_elem[0].xpath(
|
||||||
const_type = type_elem[0].strip().lower() if type_elem and type_elem[0] is not None else ""
|
"./st:ConstantValue/text()", namespaces=ns
|
||||||
const_val = val_elem[0].strip() if val_elem and val_elem[0] is not None else "_ERR_CONSTVAL_"
|
)
|
||||||
|
if not val_elem:
|
||||||
|
val_elem = constant_elem[0].xpath("./ConstantValue/text()")
|
||||||
|
|
||||||
|
# Si no hay texto directo, buscar el texto del nodo ConstantValue
|
||||||
|
if not val_elem:
|
||||||
|
val_nodes = constant_elem[0].xpath("./ConstantValue")
|
||||||
|
if val_nodes and val_nodes[0].text:
|
||||||
|
val_elem = [val_nodes[0].text]
|
||||||
|
|
||||||
|
# Buscar ConstantType tanto con namespace como sin namespace
|
||||||
|
type_elem = constant_elem[0].xpath(
|
||||||
|
"./st:ConstantType/text()", namespaces=ns
|
||||||
|
)
|
||||||
|
if not type_elem:
|
||||||
|
type_elem = constant_elem[0].xpath("./ConstantType/text()")
|
||||||
|
|
||||||
|
const_val = (
|
||||||
|
val_elem[0].strip()
|
||||||
|
if val_elem and val_elem[0] is not None
|
||||||
|
else "_ERR_CONSTVAL_"
|
||||||
|
)
|
||||||
|
const_type = (
|
||||||
|
type_elem[0].strip().lower()
|
||||||
|
if type_elem and type_elem[0] is not None
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
# Si no hay tipo explícito, inferir de acuerdo al valor
|
||||||
|
if not const_type:
|
||||||
|
if const_val.lower() in ["true", "false"]:
|
||||||
|
const_type = "bool"
|
||||||
|
elif const_val.startswith("'") and const_val.endswith("'"):
|
||||||
|
const_type = "string"
|
||||||
|
elif const_val.isdigit() or (
|
||||||
|
const_val.startswith("-") and const_val[1:].isdigit()
|
||||||
|
):
|
||||||
|
const_type = "int"
|
||||||
|
elif "." in const_val:
|
||||||
|
const_type = "real"
|
||||||
|
else:
|
||||||
|
const_type = "" # Sin tipo específico, usar valor directo
|
||||||
|
|
||||||
# Formatear según tipo
|
# Formatear según tipo
|
||||||
if const_type == "bool": access_str = const_val.upper()
|
if const_type == "bool":
|
||||||
|
access_str = const_val.upper()
|
||||||
elif const_type.lower() == "string":
|
elif const_type.lower() == "string":
|
||||||
|
if not (const_val.startswith("'") and const_val.endswith("'")):
|
||||||
replaced_val = const_val.replace("'", "''")
|
replaced_val = const_val.replace("'", "''")
|
||||||
access_str = f"'{replaced_val}'"
|
access_str = f"'{replaced_val}'"
|
||||||
|
else:
|
||||||
|
access_str = const_val
|
||||||
elif const_type.lower() == "char":
|
elif const_type.lower() == "char":
|
||||||
|
if not (const_val.startswith("'") and const_val.endswith("'")):
|
||||||
replaced_val = const_val.replace("'", "''")
|
replaced_val = const_val.replace("'", "''")
|
||||||
access_str = f"'{replaced_val}'"
|
access_str = f"'{replaced_val}'"
|
||||||
|
else:
|
||||||
|
access_str = const_val
|
||||||
elif const_type == "wstring":
|
elif const_type == "wstring":
|
||||||
replaced_val = const_val.replace("'", "''")
|
replaced_val = const_val.replace("'", "''")
|
||||||
access_str = f"WSTRING#'{replaced_val}'"
|
access_str = f"WSTRING#'{replaced_val}'"
|
||||||
elif const_type == "wchar":
|
elif const_type == "wchar":
|
||||||
replaced_val = const_val.replace("'", "''")
|
replaced_val = const_val.replace("'", "''")
|
||||||
access_str = f"WCHAR#'{replaced_val}'"
|
access_str = f"WCHAR#'{replaced_val}'"
|
||||||
elif const_type == "time": access_str = f"T#{const_val}"
|
elif const_type == "time":
|
||||||
elif const_type == "ltime": access_str = f"LT#{const_val}"
|
access_str = (
|
||||||
elif const_type == "s5time": access_str = f"S5T#{const_val}"
|
f"T#{const_val}"
|
||||||
elif const_type == "date": access_str = f"D#{const_val}"
|
if not const_val.startswith("T#")
|
||||||
elif const_type == "dtl": access_str = f"DTL#{const_val}"
|
else const_val
|
||||||
elif const_type == "dt": access_str = f"DT#{const_val}"
|
)
|
||||||
elif const_type == "tod": access_str = f"TOD#{const_val}"
|
elif const_type == "ltime":
|
||||||
elif const_type in ["int", "dint", "sint", "usint", "uint", "udint", "real", "lreal", "word", "dword", "byte"]:
|
access_str = (
|
||||||
|
f"LT#{const_val}"
|
||||||
|
if not const_val.startswith("LT#")
|
||||||
|
else const_val
|
||||||
|
)
|
||||||
|
elif const_type == "s5time":
|
||||||
|
access_str = (
|
||||||
|
f"S5T#{const_val}"
|
||||||
|
if not const_val.startswith("S5T#")
|
||||||
|
else const_val
|
||||||
|
)
|
||||||
|
elif const_type == "date":
|
||||||
|
access_str = (
|
||||||
|
f"D#{const_val}"
|
||||||
|
if not const_val.startswith("D#")
|
||||||
|
else const_val
|
||||||
|
)
|
||||||
|
elif const_type == "dtl":
|
||||||
|
access_str = (
|
||||||
|
f"DTL#{const_val}"
|
||||||
|
if not const_val.startswith("DTL#")
|
||||||
|
else const_val
|
||||||
|
)
|
||||||
|
elif const_type == "dt":
|
||||||
|
access_str = (
|
||||||
|
f"DT#{const_val}"
|
||||||
|
if not const_val.startswith("DT#")
|
||||||
|
else const_val
|
||||||
|
)
|
||||||
|
elif const_type == "tod":
|
||||||
|
access_str = (
|
||||||
|
f"TOD#{const_val}"
|
||||||
|
if not const_val.startswith("TOD#")
|
||||||
|
else const_val
|
||||||
|
)
|
||||||
|
elif const_type in [
|
||||||
|
"int",
|
||||||
|
"dint",
|
||||||
|
"sint",
|
||||||
|
"usint",
|
||||||
|
"uint",
|
||||||
|
"udint",
|
||||||
|
"real",
|
||||||
|
"lreal",
|
||||||
|
"word",
|
||||||
|
"dword",
|
||||||
|
"byte",
|
||||||
|
]:
|
||||||
# Añadir .0 para reales si no tienen decimal
|
# Añadir .0 para reales si no tienen decimal
|
||||||
if const_type in ["real", "lreal"] and '.' not in const_val and 'e' not in const_val.lower():
|
if (
|
||||||
|
const_type in ["real", "lreal"]
|
||||||
|
and "." not in const_val
|
||||||
|
and "e" not in const_val.lower()
|
||||||
|
):
|
||||||
access_str = f"{const_val}.0"
|
access_str = f"{const_val}.0"
|
||||||
else:
|
else:
|
||||||
access_str = const_val
|
access_str = const_val
|
||||||
else: # Otros tipos (LWORD, etc.) o desconocidos
|
else: # Otros tipos o sin tipo específico - usar valor directo
|
||||||
access_str = const_val
|
access_str = const_val
|
||||||
else:
|
else:
|
||||||
access_str = "/*_ERR_NOCONST_*/"
|
access_str = "/*_ERR_NOCONST_*/"
|
||||||
|
@ -140,16 +418,24 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
for p in params:
|
for p in params:
|
||||||
p_name = p.get("Name", "_ERR_PARAMNAME_")
|
p_name = p.get("Name", "_ERR_PARAMNAME_")
|
||||||
# El valor del parámetro está dentro del nodo Parameter
|
# El valor del parámetro está dentro del nodo Parameter
|
||||||
p_value_node = p.xpath("./st:Access | ./st:Token", namespaces=ns) # Buscar Access o Token
|
p_value_node = p.xpath(
|
||||||
|
"./st:Access | ./st:Token", namespaces=ns
|
||||||
|
) # Buscar Access o Token
|
||||||
p_value_scl = ""
|
p_value_scl = ""
|
||||||
if p_value_node:
|
if p_value_node:
|
||||||
p_value_scl = reconstruct_scl_from_tokens(p) # Parsear el contenido del parámetro
|
p_value_scl = reconstruct_scl_from_tokens(
|
||||||
p_value_scl = p_value_scl.replace('\n', '').strip() # Limpiar SCL resultante
|
p
|
||||||
|
) # Parsear el contenido del parámetro
|
||||||
|
p_value_scl = p_value_scl.replace(
|
||||||
|
"\n", ""
|
||||||
|
).strip() # Limpiar SCL resultante
|
||||||
param_parts.append(f"{p_name} := {p_value_scl}")
|
param_parts.append(f"{p_name} := {p_value_scl}")
|
||||||
|
|
||||||
# Manejar FB vs FC
|
# Manejar FB vs FC
|
||||||
if call_type == "FB":
|
if call_type == "FB":
|
||||||
instance_node = ci.xpath("./st:Instance/st:Component/@Name", namespaces=ns)
|
instance_node = ci.xpath(
|
||||||
|
"./st:Instance/st:Component/@Name", namespaces=ns
|
||||||
|
)
|
||||||
if instance_node:
|
if instance_node:
|
||||||
instance_name = f'"{instance_node[0]}"'
|
instance_name = f'"{instance_node[0]}"'
|
||||||
access_str = f"{instance_name}({', '.join(param_parts)})"
|
access_str = f"{instance_name}({', '.join(param_parts)})"
|
||||||
|
@ -167,12 +453,28 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
scl_parts.append(access_str)
|
scl_parts.append(access_str)
|
||||||
|
|
||||||
elif tag == "Comment" or tag == "LineComment":
|
elif tag == "Comment" or tag == "LineComment":
|
||||||
# Usar get_multilingual_text del parser_utils
|
# Manejar diferentes estructuras de comentarios
|
||||||
comment_text = get_multilingual_text(elem)
|
if tag == "LineComment":
|
||||||
if tag == "Comment":
|
# LineComment tiene estructura <Text> directa, no MultilingualText
|
||||||
|
text_elem = elem.xpath("./st:Text", namespaces=ns)
|
||||||
|
if not text_elem:
|
||||||
|
text_elem = elem.xpath("./Text")
|
||||||
|
|
||||||
|
if text_elem and text_elem[0].text:
|
||||||
|
comment_text = text_elem[0].text.strip()
|
||||||
|
# Preservar comentarios de bloque multilinea
|
||||||
|
if "\n" in comment_text:
|
||||||
|
# Comentario multilinea: usar formato (* ... *)
|
||||||
scl_parts.append(f"(* {comment_text} *)")
|
scl_parts.append(f"(* {comment_text} *)")
|
||||||
else:
|
else:
|
||||||
|
# Comentario de línea simple
|
||||||
scl_parts.append(f"// {comment_text}")
|
scl_parts.append(f"// {comment_text}")
|
||||||
|
else:
|
||||||
|
scl_parts.append("// [Comentario vacío]")
|
||||||
|
else:
|
||||||
|
# Comment tradicional: usar get_multilingual_text
|
||||||
|
comment_text = get_multilingual_text(elem)
|
||||||
|
scl_parts.append(f"(* {comment_text} *)")
|
||||||
# Ignorar otros tipos de nodos si no son relevantes para el SCL
|
# Ignorar otros tipos de nodos si no son relevantes para el SCL
|
||||||
|
|
||||||
full_scl = "".join(scl_parts)
|
full_scl = "".join(scl_parts)
|
||||||
|
@ -181,6 +483,8 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
output_lines = []
|
output_lines = []
|
||||||
indent_level = 0
|
indent_level = 0
|
||||||
indent_str = " " # Dos espacios
|
indent_str = " " # Dos espacios
|
||||||
|
case_indent_level = 0 # Nivel especial para manejar CASE statements
|
||||||
|
|
||||||
for line in full_scl.splitlines():
|
for line in full_scl.splitlines():
|
||||||
trimmed_line = line.strip()
|
trimmed_line = line.strip()
|
||||||
if not trimmed_line:
|
if not trimmed_line:
|
||||||
|
@ -188,23 +492,58 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
# output_lines.append("")
|
# output_lines.append("")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Reducir indentación ANTES de imprimir para END, ELSE, etc.
|
|
||||||
if trimmed_line.upper().startswith(("END_", "UNTIL", "}")) or \
|
|
||||||
trimmed_line.upper() in ["ELSE", "ELSIF"]:
|
|
||||||
indent_level = max(0, indent_level - 1)
|
|
||||||
|
|
||||||
output_lines.append(indent_str * indent_level + trimmed_line)
|
|
||||||
|
|
||||||
# Aumentar indentación DESPUÉS de imprimir para IF, FOR, etc.
|
|
||||||
# Ser más específico con las palabras clave que aumentan indentación
|
|
||||||
# Usar .upper() para ignorar mayúsculas/minúsculas
|
|
||||||
line_upper = trimmed_line.upper()
|
line_upper = trimmed_line.upper()
|
||||||
if line_upper.endswith(("THEN", "DO", "OF", "{")) or \
|
|
||||||
line_upper.startswith(("IF ", "FOR ", "WHILE ", "CASE ", "REPEAT", "STRUCT")) or \
|
# Detectar labels de CASE (pattern: #SomeName: o SomeName:)
|
||||||
line_upper == "ELSE":
|
is_case_label = (
|
||||||
|
":" in trimmed_line
|
||||||
|
and (
|
||||||
|
trimmed_line.startswith("#")
|
||||||
|
or not any(
|
||||||
|
keyword in line_upper for keyword in ["IF", "ELSIF", "ELSE", "THEN"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
and line_upper not in ["ELSE:", "ELSIF:"]
|
||||||
|
and "//" not in trimmed_line.split(":")[0] # Evitar comentarios
|
||||||
|
)
|
||||||
|
|
||||||
|
# Reducir indentación ANTES de imprimir para ciertas palabras clave
|
||||||
|
if line_upper.startswith(("END_", "UNTIL", "}")):
|
||||||
|
indent_level = max(0, indent_level - 1)
|
||||||
|
if line_upper.startswith("END_CASE"):
|
||||||
|
case_indent_level = 0
|
||||||
|
elif line_upper in ["ELSE", "ELSIF"] and not is_case_label:
|
||||||
|
indent_level = max(0, indent_level - 1)
|
||||||
|
elif is_case_label and case_indent_level > 0:
|
||||||
|
# Los labels de case van un nivel menos indentados que el contenido del case
|
||||||
|
indent_level = max(0, case_indent_level)
|
||||||
|
|
||||||
|
# Aplicar indentación
|
||||||
|
current_indent = indent_level
|
||||||
|
if is_case_label and case_indent_level > 0:
|
||||||
|
# Los labels de case van un nivel menos que el contenido normal
|
||||||
|
current_indent = case_indent_level
|
||||||
|
|
||||||
|
output_lines.append(indent_str * current_indent + trimmed_line)
|
||||||
|
|
||||||
|
# Aumentar indentación DESPUÉS de imprimir para ciertas palabras clave
|
||||||
|
if line_upper.endswith(("THEN", "DO", "{")) or line_upper == "ELSE":
|
||||||
# Excepción: No indentar después de ELSE IF
|
# Excepción: No indentar después de ELSE IF
|
||||||
if not (line_upper == "ELSE" and "IF" in output_lines[-1].upper()):
|
if not (
|
||||||
|
line_upper == "ELSE"
|
||||||
|
and len(output_lines) > 0
|
||||||
|
and "IF" in output_lines[-1].upper()
|
||||||
|
):
|
||||||
indent_level += 1
|
indent_level += 1
|
||||||
|
elif line_upper.startswith(("IF ", "FOR ", "WHILE ", "REPEAT", "STRUCT")):
|
||||||
|
indent_level += 1
|
||||||
|
elif line_upper.startswith("CASE ") and line_upper.endswith(" OF"):
|
||||||
|
# Manejar CASE especialmente
|
||||||
|
case_indent_level = indent_level + 1
|
||||||
|
indent_level += 1
|
||||||
|
elif is_case_label and case_indent_level > 0:
|
||||||
|
# Después de un label de case, el contenido va un nivel más indentado
|
||||||
|
indent_level = case_indent_level + 1
|
||||||
|
|
||||||
return "\n".join(output_lines)
|
return "\n".join(output_lines)
|
||||||
|
|
||||||
|
@ -221,7 +560,9 @@ def parse_scl_network(network_element):
|
||||||
title_elem = network_element.xpath(
|
title_elem = network_element.xpath(
|
||||||
"./ObjectList/MultilingualText[@CompositionName='Title']", namespaces=ns
|
"./ObjectList/MultilingualText[@CompositionName='Title']", namespaces=ns
|
||||||
)
|
)
|
||||||
network_title = get_multilingual_text(title_elem[0]) if title_elem else f"Network {network_id}"
|
network_title = (
|
||||||
|
get_multilingual_text(title_elem[0]) if title_elem else f"Network {network_id}"
|
||||||
|
)
|
||||||
|
|
||||||
comment_elem = network_element.xpath(
|
comment_elem = network_element.xpath(
|
||||||
"./ObjectList/MultilingualText[@CompositionName='Comment']", namespaces=ns
|
"./ObjectList/MultilingualText[@CompositionName='Comment']", namespaces=ns
|
||||||
|
@ -255,10 +596,11 @@ def parse_scl_network(network_element):
|
||||||
}
|
}
|
||||||
return parsed_network_data
|
return parsed_network_data
|
||||||
|
|
||||||
|
|
||||||
# --- Función de Información del Parser ---
|
# --- Función de Información del Parser ---
|
||||||
def get_parser_info():
|
def get_parser_info():
|
||||||
"""Devuelve la información para este parser."""
|
"""Devuelve la información para este parser."""
|
||||||
return {
|
return {
|
||||||
'language': ['SCL'], # Lista de lenguajes soportados
|
"language": ["SCL"], # Lista de lenguajes soportados
|
||||||
'parser_func': parse_scl_network # Función a llamar
|
"parser_func": parse_scl_network, # Función a llamar
|
||||||
}
|
}
|
|
@ -19,20 +19,25 @@ def get_multilingual_text(element, default_lang="en-US-it-IT", fallback_lang=Non
|
||||||
Extrae texto multilingüe de un elemento XML. (v5.2 - DEBUG + XPath ObjectList)
|
Extrae texto multilingüe de un elemento XML. (v5.2 - DEBUG + XPath ObjectList)
|
||||||
"""
|
"""
|
||||||
# print(f"--- DEBUG get_multilingual_text v5.2: Iniciando para elemento {element.tag if element is not None else 'None'}, default='{default_lang}' ---")
|
# print(f"--- DEBUG get_multilingual_text v5.2: Iniciando para elemento {element.tag if element is not None else 'None'}, default='{default_lang}' ---")
|
||||||
if element is None: return ""
|
if element is None:
|
||||||
|
return ""
|
||||||
|
|
||||||
combined_texts = []
|
combined_texts = []
|
||||||
languages_to_try = []
|
languages_to_try = []
|
||||||
|
|
||||||
# --- Lógica Combinada ---
|
# --- Lógica Combinada ---
|
||||||
is_combined_mode = default_lang and '-' in default_lang and len(default_lang.split('-')) >= 2
|
is_combined_mode = (
|
||||||
|
default_lang and "-" in default_lang and len(default_lang.split("-")) >= 2
|
||||||
|
)
|
||||||
if is_combined_mode:
|
if is_combined_mode:
|
||||||
# print(f"--- DEBUG v5.2: Detectado modo combinado: '{default_lang}' ---")
|
# print(f"--- DEBUG v5.2: Detectado modo combinado: '{default_lang}' ---")
|
||||||
parts = default_lang.split('-')
|
parts = default_lang.split("-")
|
||||||
target_langs = []
|
target_langs = []
|
||||||
if len(parts) % 2 == 0:
|
if len(parts) % 2 == 0:
|
||||||
for i in range(0, len(parts), 2): target_langs.append(f"{parts[i]}-{parts[i+1]}")
|
for i in range(0, len(parts), 2):
|
||||||
else: target_langs = []
|
target_langs.append(f"{parts[i]}-{parts[i+1]}")
|
||||||
|
else:
|
||||||
|
target_langs = []
|
||||||
|
|
||||||
if target_langs:
|
if target_langs:
|
||||||
# print(f"--- DEBUG v5.2: Culturas combinadas a buscar: {target_langs} ---")
|
# print(f"--- DEBUG v5.2: Culturas combinadas a buscar: {target_langs} ---")
|
||||||
|
@ -50,7 +55,8 @@ def get_multilingual_text(element, default_lang="en-US-it-IT", fallback_lang=Non
|
||||||
if text_nodes:
|
if text_nodes:
|
||||||
text_content = text_nodes[0].strip()
|
text_content = text_nodes[0].strip()
|
||||||
# print(f" DEBUG Combinado v5.2: Texto encontrado para '{lang}': '{text_content[:50]}...'")
|
# print(f" DEBUG Combinado v5.2: Texto encontrado para '{lang}': '{text_content[:50]}...'")
|
||||||
if text_content: combined_texts.append(text_content)
|
if text_content:
|
||||||
|
combined_texts.append(text_content)
|
||||||
# --- FIN CORRECCIÓN XPath v5.2 ---
|
# --- FIN CORRECCIÓN XPath v5.2 ---
|
||||||
if combined_texts:
|
if combined_texts:
|
||||||
# print(f"--- DEBUG v5.2: Modo combinado retornando: '{' - '.join(combined_texts)}' ---")
|
# print(f"--- DEBUG v5.2: Modo combinado retornando: '{' - '.join(combined_texts)}' ---")
|
||||||
|
@ -59,22 +65,29 @@ def get_multilingual_text(element, default_lang="en-US-it-IT", fallback_lang=Non
|
||||||
# print(f"--- DEBUG v5.2: Modo combinado no encontró textos. Intentando fallback... ---")
|
# print(f"--- DEBUG v5.2: Modo combinado no encontró textos. Intentando fallback... ---")
|
||||||
default_lang = None
|
default_lang = None
|
||||||
except Exception as e_comb:
|
except Exception as e_comb:
|
||||||
print(f" Advertencia: Error procesando modo combinado '{default_lang}': {e_comb}")
|
print(
|
||||||
|
f" Advertencia: Error procesando modo combinado '{default_lang}': {e_comb}"
|
||||||
|
)
|
||||||
|
default_lang = None
|
||||||
|
else:
|
||||||
default_lang = None
|
default_lang = None
|
||||||
else: default_lang = None
|
|
||||||
# --- Fin Lógica Combinada ---
|
# --- Fin Lógica Combinada ---
|
||||||
|
|
||||||
# --- Lógica Normal / Fallback ---
|
# --- Lógica Normal / Fallback ---
|
||||||
# print("--- DEBUG v5.2: Iniciando lógica Normal/Fallback ---")
|
# print("--- DEBUG v5.2: Iniciando lógica Normal/Fallback ---")
|
||||||
if default_lang: languages_to_try.append(default_lang)
|
if default_lang:
|
||||||
if fallback_lang: languages_to_try.append(fallback_lang)
|
languages_to_try.append(default_lang)
|
||||||
|
if fallback_lang:
|
||||||
|
languages_to_try.append(fallback_lang)
|
||||||
# print(f" DEBUG v5.2: Idiomas específicos a probar: {languages_to_try}")
|
# print(f" DEBUG v5.2: Idiomas específicos a probar: {languages_to_try}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if languages_to_try:
|
if languages_to_try:
|
||||||
for lang in languages_to_try:
|
for lang in languages_to_try:
|
||||||
# --- CORRECCIÓN XPath v5.2: Añadir ObjectList ---
|
# --- CORRECCIÓN XPath v5.2: Añadir ObjectList ---
|
||||||
xpath_find_item = f"./ObjectList/MultilingualTextItem[AttributeList/Culture='{lang}']"
|
xpath_find_item = (
|
||||||
|
f"./ObjectList/MultilingualTextItem[AttributeList/Culture='{lang}']"
|
||||||
|
)
|
||||||
found_items = element.xpath(xpath_find_item, namespaces=ns)
|
found_items = element.xpath(xpath_find_item, namespaces=ns)
|
||||||
# print(f" DEBUG Fallback v5.2: Items encontrados para '{lang}': {len(found_items)}")
|
# print(f" DEBUG Fallback v5.2: Items encontrados para '{lang}': {len(found_items)}")
|
||||||
if found_items:
|
if found_items:
|
||||||
|
@ -110,10 +123,15 @@ def get_multilingual_text(element, default_lang="en-US-it-IT", fallback_lang=Non
|
||||||
|
|
||||||
|
|
||||||
def get_symbol_name(symbol_element):
|
def get_symbol_name(symbol_element):
|
||||||
"""Obtiene el nombre completo de un símbolo desde un elemento <flg:Symbol>."""
|
"""Obtiene el nombre completo de un símbolo desde un elemento <flg:Symbol>, incluyendo índices de arrays."""
|
||||||
if symbol_element is None:
|
if symbol_element is None:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
|
# Obtener todos los elementos Component
|
||||||
|
component_elements = symbol_element.xpath("./flg:Component", namespaces=ns)
|
||||||
|
|
||||||
|
if not component_elements:
|
||||||
|
# Fallback al método anterior si no se encuentran elementos Component
|
||||||
components = symbol_element.xpath("./flg:Component/@Name", namespaces=ns)
|
components = symbol_element.xpath("./flg:Component/@Name", namespaces=ns)
|
||||||
return (
|
return (
|
||||||
".".join(
|
".".join(
|
||||||
|
@ -123,6 +141,58 @@ def get_symbol_name(symbol_element):
|
||||||
if components
|
if components
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
symbol_parts = []
|
||||||
|
|
||||||
|
for i, comp in enumerate(component_elements):
|
||||||
|
comp_name = comp.get("Name", "_ERR_COMP_NAME_")
|
||||||
|
|
||||||
|
# Añadir separador de punto si no es el primer componente
|
||||||
|
if i > 0:
|
||||||
|
symbol_parts.append(".")
|
||||||
|
|
||||||
|
# Formatear el nombre del componente
|
||||||
|
if not comp_name.startswith("#") and '"' not in comp_name:
|
||||||
|
symbol_parts.append(f'"{comp_name}"')
|
||||||
|
else:
|
||||||
|
symbol_parts.append(comp_name)
|
||||||
|
|
||||||
|
# Buscar accesos de array dentro del componente
|
||||||
|
# Buscar tanto con namespace flg: como sin namespace
|
||||||
|
access_elements = comp.xpath("./flg:Access", namespaces=ns)
|
||||||
|
if not access_elements:
|
||||||
|
access_elements = comp.xpath("./Access")
|
||||||
|
|
||||||
|
if access_elements:
|
||||||
|
indices_parts = []
|
||||||
|
for access_elem in access_elements:
|
||||||
|
access_scope = access_elem.get("Scope")
|
||||||
|
|
||||||
|
if access_scope == "LiteralConstant":
|
||||||
|
# Buscar el valor de la constante
|
||||||
|
const_elem = access_elem.xpath("./flg:Constant", namespaces=ns)
|
||||||
|
if not const_elem:
|
||||||
|
const_elem = access_elem.xpath("./Constant")
|
||||||
|
|
||||||
|
if const_elem:
|
||||||
|
val_elem = const_elem[0].xpath(
|
||||||
|
"./flg:ConstantValue", namespaces=ns
|
||||||
|
)
|
||||||
|
if not val_elem:
|
||||||
|
val_elem = const_elem[0].xpath("./ConstantValue")
|
||||||
|
|
||||||
|
if val_elem and val_elem[0].text:
|
||||||
|
indices_parts.append(val_elem[0].text.strip())
|
||||||
|
else:
|
||||||
|
# Para otros tipos de acceso, podríamos implementar lógica adicional
|
||||||
|
# Por ahora, añadir un marcador de error
|
||||||
|
indices_parts.append(f"/*_ERR_COMPLEX_INDEX_{access_scope}_*/")
|
||||||
|
|
||||||
|
if indices_parts:
|
||||||
|
symbol_parts.append(f"[{','.join(indices_parts)}]")
|
||||||
|
|
||||||
|
return "".join(symbol_parts) if symbol_parts else None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Advertencia: Excepción en get_symbol_name: {e}")
|
print(f"Advertencia: Excepción en get_symbol_name: {e}")
|
||||||
return None
|
return None
|
||||||
|
@ -142,7 +212,9 @@ def parse_access(access_element):
|
||||||
if address_elem:
|
if address_elem:
|
||||||
addr = address_elem[0]
|
addr = address_elem[0]
|
||||||
# Extraer toda la información disponible sobre la dirección
|
# Extraer toda la información disponible sobre la dirección
|
||||||
info["type"] = "unknown_structure" # Mantener compatible con el código existente
|
info["type"] = (
|
||||||
|
"unknown_structure" # Mantener compatible con el código existente
|
||||||
|
)
|
||||||
info["Area"] = addr.get("Area", "DB")
|
info["Area"] = addr.get("Area", "DB")
|
||||||
info["BitOffset"] = addr.get("BitOffset", "0")
|
info["BitOffset"] = addr.get("BitOffset", "0")
|
||||||
info["BlockNumber"] = addr.get("BlockNumber", "")
|
info["BlockNumber"] = addr.get("BlockNumber", "")
|
||||||
|
@ -262,6 +334,7 @@ def parse_access(access_element):
|
||||||
info["type"] = "error_no_name"
|
info["type"] = "error_no_name"
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
def parse_part(part_element):
|
def parse_part(part_element):
|
||||||
"""Parsea un nodo <flg:Part> de LAD/FBD."""
|
"""Parsea un nodo <flg:Part> de LAD/FBD."""
|
||||||
if part_element is None:
|
if part_element is None:
|
||||||
|
@ -279,7 +352,9 @@ def parse_part(part_element):
|
||||||
for tv in part_element.xpath("./flg:TemplateValue", namespaces=ns):
|
for tv in part_element.xpath("./flg:TemplateValue", namespaces=ns):
|
||||||
tv_name = tv.get("Name")
|
tv_name = tv.get("Name")
|
||||||
tv_type = tv.get("Type")
|
tv_type = tv.get("Type")
|
||||||
tv_value = tv.text.strip() if tv.text else tv_type # Obtener valor real del elemento
|
tv_value = (
|
||||||
|
tv.text.strip() if tv.text else tv_type
|
||||||
|
) # Obtener valor real del elemento
|
||||||
if tv_name:
|
if tv_name:
|
||||||
template_values[tv_name] = tv_value
|
template_values[tv_name] = tv_value
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -480,8 +555,10 @@ def parse_interface_members(member_elements):
|
||||||
members_data.append(member_info)
|
members_data.append(member_info)
|
||||||
return members_data
|
return members_data
|
||||||
|
|
||||||
|
|
||||||
# --- NUEVA FUNCIÓN: Adaptación dinámica de namespaces ---
|
# --- NUEVA FUNCIÓN: Adaptación dinámica de namespaces ---
|
||||||
|
|
||||||
|
|
||||||
def adapt_namespaces(root):
|
def adapt_namespaces(root):
|
||||||
"""Actualiza dinámicamente los valores en el diccionario global `ns` para que
|
"""Actualiza dinámicamente los valores en el diccionario global `ns` para que
|
||||||
coincidan con los namespaces reales presentes en el XML exportado por TIA.
|
coincidan con los namespaces reales presentes en el XML exportado por TIA.
|
||||||
|
@ -540,6 +617,7 @@ def adapt_namespaces(root):
|
||||||
|
|
||||||
# --- función auxiliar privada para adapt_namespaces ---
|
# --- función auxiliar privada para adapt_namespaces ---
|
||||||
|
|
||||||
|
|
||||||
def _assign_uri_to_prefix(uri_str: str, out_dict: dict):
|
def _assign_uri_to_prefix(uri_str: str, out_dict: dict):
|
||||||
"""Asigna un URI concreto al prefijo adecuado en `out_dict`."""
|
"""Asigna un URI concreto al prefijo adecuado en `out_dict`."""
|
||||||
if "/Interface/" in uri_str:
|
if "/Interface/" in uri_str:
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"display_name": "2: Procesar un archivo individual usando x4",
|
"display_name": "2: Procesar un archivo individual usando x4",
|
||||||
"short_description": "LadderToSCL - Conversor de Siemens LAD/FUP XML a SCL",
|
"short_description": "LadderToSCL - Conversor de Siemens LAD/FUP XML a SCL",
|
||||||
"long_description": "",
|
"long_description": "",
|
||||||
"hidden": false
|
"hidden": true
|
||||||
},
|
},
|
||||||
"x5_aggregate.py": {
|
"x5_aggregate.py": {
|
||||||
"display_name": "x5_aggregate",
|
"display_name": "x5_aggregate",
|
||||||
|
@ -40,5 +40,23 @@
|
||||||
"short_description": "3: Limpiar archivos json y md generados por (1)",
|
"short_description": "3: Limpiar archivos json y md generados por (1)",
|
||||||
"long_description": "",
|
"long_description": "",
|
||||||
"hidden": false
|
"hidden": false
|
||||||
|
},
|
||||||
|
"debug_array_parsing.py": {
|
||||||
|
"display_name": "debug_array_parsing",
|
||||||
|
"short_description": "Sin descripción corta.",
|
||||||
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"test_conversion.py": {
|
||||||
|
"display_name": "test_conversion",
|
||||||
|
"short_description": "Sin descripción corta.",
|
||||||
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"x8_manual_gui.py": {
|
||||||
|
"display_name": "2: Procesar un archivo individual",
|
||||||
|
"short_description": "x8_manual_gui.py - Interfaz Manual con GUI para XML→SCL",
|
||||||
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Script de prueba para verificar que los índices de arrays se capturen correctamente en LAD/FBD."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Añadir el directorio padre al path para los imports
|
||||||
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
|
||||||
|
from x1_to_json import convert_xml_to_json
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
xml_file = ".example/FC TT Devices.xml"
|
||||||
|
json_file = ".example/FC_TT_Devices_test.json"
|
||||||
|
|
||||||
|
print(f"Probando conversión de {xml_file} a {json_file}...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
success = convert_xml_to_json(xml_file, json_file)
|
||||||
|
if success:
|
||||||
|
print("Conversión exitosa!")
|
||||||
|
|
||||||
|
# Buscar patrones de arrays en el JSON generado
|
||||||
|
with open(json_file, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Buscar di0.x con índices
|
||||||
|
if '"di0.x"[1]' in content:
|
||||||
|
print(
|
||||||
|
"✅ ÉXITO: Se encontró di0.x[1] - los índices de arrays se están capturando correctamente!"
|
||||||
|
)
|
||||||
|
elif '"di0.x"[]' in content:
|
||||||
|
print("❌ PROBLEMA: Se encontró di0.x[] - los índices están vacíos")
|
||||||
|
elif '"di0.x"' in content:
|
||||||
|
print(
|
||||||
|
"❌ PROBLEMA: Se encontró di0.x sin índices - el fix no está funcionando"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print("⚠️ No se encontró di0.x en el contenido")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Error en la conversión")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
traceback.print_exc()
|
|
@ -1,13 +1,6 @@
|
||||||
{
|
{
|
||||||
"path": "D:\\Trabajo\\VM\\45 - HENKEL - VM Auto Changeover\\ExportTia",
|
"path": "D:\\Trabajo\\VM\\45 - HENKEL - VM Auto Changeover\\ExportTia",
|
||||||
"history": [
|
"history": [
|
||||||
"D:\\Trabajo\\VM\\45 - HENKEL - VM Auto Changeover\\ExportTia",
|
"D:\\Trabajo\\VM\\45 - HENKEL - VM Auto Changeover\\ExportTia"
|
||||||
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giorgio in Bosco\\Reporte\\TiaExport",
|
|
||||||
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\TiaExport",
|
|
||||||
"D:\\Trabajo\\VM\\44 - 98050 - Fiera\\Reporte\\ExportsTia\\Source",
|
|
||||||
"C:\\Trabajo\\SIDEL\\13 - E5.007560 - Modifica O&U - SAE235\\Reporte\\ExportTia",
|
|
||||||
"D:\\Trabajo\\VM\\22 - 93841 - Sidel - Tilting\\Reporte\\TiaExports",
|
|
||||||
"C:\\Trabajo\\SIDEL\\09 - SAE452 - Diet as Regular - San Giovanni in Bosco\\Reporte\\SourceDoc\\SourceXML",
|
|
||||||
"C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\IOExport"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@ import traceback
|
||||||
import json
|
import json
|
||||||
import datetime # <-- NUEVO: Para timestamps
|
import datetime # <-- NUEVO: Para timestamps
|
||||||
import shutil # <-- ADDED: Import shutil for file copying
|
import shutil # <-- ADDED: Import shutil for file copying
|
||||||
|
|
||||||
script_root = os.path.dirname(
|
script_root = os.path.dirname(
|
||||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||||
)
|
)
|
||||||
|
@ -28,8 +29,11 @@ from backend.script_utils import load_configuration
|
||||||
from x1_to_json import convert_xml_to_json
|
from x1_to_json import convert_xml_to_json
|
||||||
from x2_process import process_json_to_scl
|
from x2_process import process_json_to_scl
|
||||||
from x3_generate_scl import generate_scl_or_markdown
|
from x3_generate_scl import generate_scl_or_markdown
|
||||||
|
|
||||||
# <-- NUEVO: Importar funciones de x4 y x5 -->
|
# <-- NUEVO: Importar funciones de x4 y x5 -->
|
||||||
from x4_cross_reference import generate_cross_references # Asumiendo que x4_cross_reference.py tiene esta función
|
from x4_cross_reference import (
|
||||||
|
generate_cross_references,
|
||||||
|
) # Asumiendo que x4_cross_reference.py tiene esta función
|
||||||
from x5_aggregate import aggregate_outputs
|
from x5_aggregate import aggregate_outputs
|
||||||
|
|
||||||
|
|
||||||
|
@ -160,6 +164,7 @@ def check_skip_status(
|
||||||
|
|
||||||
# --- FUNCIÓN DE LIMPIEZA (x7) ---------------------------------------------------------------------------
|
# --- FUNCIÓN DE LIMPIEZA (x7) ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def clear_generated_outputs(plc_dir: str = None) -> bool:
|
def clear_generated_outputs(plc_dir: str = None) -> bool:
|
||||||
"""Elimina todos los artefactos (JSON, SCL, MD, logs) generados por este script.
|
"""Elimina todos los artefactos (JSON, SCL, MD, logs) generados por este script.
|
||||||
|
|
||||||
|
@ -174,25 +179,36 @@ def clear_generated_outputs(plc_dir: str = None) -> bool:
|
||||||
configs = load_configuration()
|
configs = load_configuration()
|
||||||
working_directory = configs.get("working_directory")
|
working_directory = configs.get("working_directory")
|
||||||
if not working_directory or not os.path.isdir(working_directory):
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
print("Error: 'working_directory' inválido en la configuración.", file=sys.stderr)
|
print(
|
||||||
|
"Error: 'working_directory' inválido en la configuración.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
xml_parser_config = configs.get("level2", {})
|
xml_parser_config = configs.get("level2", {})
|
||||||
cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output")
|
cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output")
|
||||||
cfg_xref_output_dirname = xml_parser_config.get("xref_output_dir", "xref_output")
|
cfg_xref_output_dirname = xml_parser_config.get(
|
||||||
cfg_aggregated_filename = xml_parser_config.get("aggregated_filename", "full_project_representation.md")
|
"xref_output_dir", "xref_output"
|
||||||
|
)
|
||||||
|
cfg_aggregated_filename = xml_parser_config.get(
|
||||||
|
"aggregated_filename", "full_project_representation.md"
|
||||||
|
)
|
||||||
|
|
||||||
# Determinar la lista de PLCs a limpiar
|
# Determinar la lista de PLCs a limpiar
|
||||||
if plc_dir is not None:
|
if plc_dir is not None:
|
||||||
plc_dirs = [os.path.abspath(plc_dir)]
|
plc_dirs = [os.path.abspath(plc_dir)]
|
||||||
if not os.path.isdir(plc_dirs[0]):
|
if not os.path.isdir(plc_dirs[0]):
|
||||||
print(f"Advertencia: El directorio PLC especificado no existe: {plc_dirs[0]}")
|
print(
|
||||||
|
f"Advertencia: El directorio PLC especificado no existe: {plc_dirs[0]}"
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
plc_dirs = []
|
plc_dirs = []
|
||||||
for entry in os.listdir(working_directory):
|
for entry in os.listdir(working_directory):
|
||||||
cand_path = os.path.join(working_directory, entry)
|
cand_path = os.path.join(working_directory, entry)
|
||||||
if os.path.isdir(cand_path) and glob.glob(os.path.join(cand_path, "**", "*.xml"), recursive=True):
|
if os.path.isdir(cand_path) and glob.glob(
|
||||||
|
os.path.join(cand_path, "**", "*.xml"), recursive=True
|
||||||
|
):
|
||||||
plc_dirs.append(cand_path)
|
plc_dirs.append(cand_path)
|
||||||
if not plc_dirs:
|
if not plc_dirs:
|
||||||
plc_dirs = [working_directory]
|
plc_dirs = [working_directory]
|
||||||
|
@ -206,11 +222,15 @@ def clear_generated_outputs(plc_dir: str = None) -> bool:
|
||||||
print(f"\n=== Limpiando PLC: {plc_name_safe} ===")
|
print(f"\n=== Limpiando PLC: {plc_name_safe} ===")
|
||||||
|
|
||||||
# 1) Eliminar carpetas 'parsing' (y su contenido JSON)
|
# 1) Eliminar carpetas 'parsing' (y su contenido JSON)
|
||||||
for parsing_dir in glob.glob(os.path.join(plc_path, "**", "parsing"), recursive=True):
|
for parsing_dir in glob.glob(
|
||||||
|
os.path.join(plc_path, "**", "parsing"), recursive=True
|
||||||
|
):
|
||||||
if os.path.isdir(parsing_dir):
|
if os.path.isdir(parsing_dir):
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(parsing_dir)
|
shutil.rmtree(parsing_dir)
|
||||||
print(f" - Eliminado directorio de parsing: {os.path.relpath(parsing_dir, working_directory)}")
|
print(
|
||||||
|
f" - Eliminado directorio de parsing: {os.path.relpath(parsing_dir, working_directory)}"
|
||||||
|
)
|
||||||
total_dirs_removed += 1
|
total_dirs_removed += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" - ERROR al eliminar {parsing_dir}: {e}")
|
print(f" - ERROR al eliminar {parsing_dir}: {e}")
|
||||||
|
@ -222,7 +242,9 @@ def clear_generated_outputs(plc_dir: str = None) -> bool:
|
||||||
if os.path.isdir(target_dir):
|
if os.path.isdir(target_dir):
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(target_dir)
|
shutil.rmtree(target_dir)
|
||||||
print(f" - Eliminado directorio '{dirname}': {os.path.relpath(target_dir, working_directory)}")
|
print(
|
||||||
|
f" - Eliminado directorio '{dirname}': {os.path.relpath(target_dir, working_directory)}"
|
||||||
|
)
|
||||||
total_dirs_removed += 1
|
total_dirs_removed += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" - ERROR al eliminar {target_dir}: {e}")
|
print(f" - ERROR al eliminar {target_dir}: {e}")
|
||||||
|
@ -233,7 +255,9 @@ def clear_generated_outputs(plc_dir: str = None) -> bool:
|
||||||
if os.path.isfile(agg_file):
|
if os.path.isfile(agg_file):
|
||||||
try:
|
try:
|
||||||
os.remove(agg_file)
|
os.remove(agg_file)
|
||||||
print(f" - Eliminado archivo agregado: {os.path.relpath(agg_file, working_directory)}")
|
print(
|
||||||
|
f" - Eliminado archivo agregado: {os.path.relpath(agg_file, working_directory)}"
|
||||||
|
)
|
||||||
total_files_removed += 1
|
total_files_removed += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" - ERROR al eliminar {agg_file}: {e}")
|
print(f" - ERROR al eliminar {agg_file}: {e}")
|
||||||
|
@ -254,7 +278,11 @@ def clear_generated_outputs(plc_dir: str = None) -> bool:
|
||||||
print("\n--- Resumen de limpieza ---")
|
print("\n--- Resumen de limpieza ---")
|
||||||
print(f" Directorios eliminados: {total_dirs_removed}")
|
print(f" Directorios eliminados: {total_dirs_removed}")
|
||||||
print(f" Archivos eliminados: {total_files_removed}")
|
print(f" Archivos eliminados: {total_files_removed}")
|
||||||
print(" Limpieza completada." if not errors_found else " Limpieza completada con errores.")
|
print(
|
||||||
|
" Limpieza completada."
|
||||||
|
if not errors_found
|
||||||
|
else " Limpieza completada con errores."
|
||||||
|
)
|
||||||
|
|
||||||
return not errors_found
|
return not errors_found
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -262,6 +290,7 @@ def clear_generated_outputs(plc_dir: str = None) -> bool:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
# --- FIN FUNCIÓN DE LIMPIEZA -----------------------------------------------------------------------------
|
# --- FIN FUNCIÓN DE LIMPIEZA -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,12 +299,33 @@ if __name__ == "__main__":
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# 1. Analizar argumentos de línea de comandos
|
# 1. Analizar argumentos de línea de comandos
|
||||||
# --plc-dir : ruta al PLC a procesar directamente (modo interno)
|
# --plc-dir : ruta al PLC a procesar directamente (modo interno)
|
||||||
# Si NO se pasa el flag, el script actuará como "orquestador" detectando
|
# --source-xml : archivo XML específico a convertir (modo simple)
|
||||||
|
# --dest-scl : archivo SCL de destino (modo simple)
|
||||||
|
# Si NO se pasa ningún flag, el script actuará como "orquestador" detectando
|
||||||
# todos los PLCs bajo el working_directory y lanzándose a sí mismo para
|
# todos los PLCs bajo el working_directory y lanzándose a sí mismo para
|
||||||
# cada uno de ellos.
|
# cada uno de ellos.
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
arg_parser = argparse.ArgumentParser(description="Convertidor XML→SCL (multi-PLC)")
|
arg_parser = argparse.ArgumentParser(
|
||||||
arg_parser.add_argument("--plc-dir", dest="plc_dir", help="Ruta del PLC a procesar (uso interno).", default=None)
|
description="Convertidor XML→SCL (multi-PLC o archivo único)"
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"--plc-dir",
|
||||||
|
dest="plc_dir",
|
||||||
|
help="Ruta del PLC a procesar (uso interno).",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"--source-xml",
|
||||||
|
dest="source_xml",
|
||||||
|
help="Archivo XML específico a convertir (modo simple).",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"--dest-scl",
|
||||||
|
dest="dest_scl",
|
||||||
|
help="Archivo SCL de destino (modo simple).",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
cli_args, _ = arg_parser.parse_known_args()
|
cli_args, _ = arg_parser.parse_known_args()
|
||||||
|
|
||||||
# Cargar configuración
|
# Cargar configuración
|
||||||
|
@ -283,13 +333,109 @@ if __name__ == "__main__":
|
||||||
working_directory = configs.get("working_directory")
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# 2. Si NO se indicó --plc-dir ⇒ modo ORQUESTADOR
|
# 2. Si se especificaron --source-xml y --dest-scl ⇒ modo SIMPLE
|
||||||
|
# Convierte un archivo XML específico a un archivo SCL específico.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
if cli_args.source_xml is not None or cli_args.dest_scl is not None:
|
||||||
|
# Validar que ambos argumentos estén presentes
|
||||||
|
if cli_args.source_xml is None or cli_args.dest_scl is None:
|
||||||
|
print(
|
||||||
|
"Error: Para el modo simple, ambos argumentos --source-xml y --dest-scl son requeridos.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Validar que el archivo XML existe
|
||||||
|
source_xml_path = os.path.abspath(cli_args.source_xml)
|
||||||
|
if not os.path.isfile(source_xml_path):
|
||||||
|
print(
|
||||||
|
f"Error: El archivo XML especificado no existe: {source_xml_path}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Validar que el directorio de destino existe
|
||||||
|
dest_scl_path = os.path.abspath(cli_args.dest_scl)
|
||||||
|
dest_dir = os.path.dirname(dest_scl_path)
|
||||||
|
if not os.path.exists(dest_dir):
|
||||||
|
os.makedirs(dest_dir, exist_ok=True)
|
||||||
|
print(f"Directorio de destino creado: {dest_dir}")
|
||||||
|
|
||||||
|
print(f"=== MODO SIMPLE: Convertir {source_xml_path} → {dest_scl_path} ===")
|
||||||
|
|
||||||
|
# Crear directorios temporales para el procesamiento
|
||||||
|
base_filename = os.path.splitext(os.path.basename(source_xml_path))[0]
|
||||||
|
temp_dir = os.path.join(os.path.dirname(source_xml_path), "parsing")
|
||||||
|
os.makedirs(temp_dir, exist_ok=True)
|
||||||
|
|
||||||
|
json_output_file = os.path.join(temp_dir, f"{base_filename}.json")
|
||||||
|
processed_json_file = os.path.join(temp_dir, f"{base_filename}_processed.json")
|
||||||
|
|
||||||
|
success = False
|
||||||
|
try:
|
||||||
|
# Paso 1: XML → JSON
|
||||||
|
print("Paso 1/3: Convirtiendo XML a JSON...")
|
||||||
|
success_x1 = convert_xml_to_json(source_xml_path, json_output_file)
|
||||||
|
if not success_x1:
|
||||||
|
print("ERROR: Falló la conversión XML → JSON")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Paso 2: JSON → JSON procesado
|
||||||
|
print("Paso 2/3: Procesando JSON...")
|
||||||
|
success_x2 = process_json_to_scl(json_output_file, processed_json_file)
|
||||||
|
if not success_x2:
|
||||||
|
print("ERROR: Falló el procesamiento del JSON")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Paso 3: JSON procesado → SCL/MD
|
||||||
|
print("Paso 3/3: Generando archivo de salida...")
|
||||||
|
# Para el modo simple, usamos un directorio temporal como salida
|
||||||
|
temp_output_dir = os.path.join(
|
||||||
|
os.path.dirname(dest_scl_path), "temp_scl_output"
|
||||||
|
)
|
||||||
|
os.makedirs(temp_output_dir, exist_ok=True)
|
||||||
|
|
||||||
|
success_x3 = generate_scl_or_markdown(
|
||||||
|
processed_json_file, temp_output_dir, os.path.dirname(source_xml_path)
|
||||||
|
)
|
||||||
|
if not success_x3:
|
||||||
|
print("ERROR: Falló la generación del archivo final")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Encontrar el archivo generado y moverlo al destino final
|
||||||
|
generated_files = glob.glob(os.path.join(temp_output_dir, "*"))
|
||||||
|
if not generated_files:
|
||||||
|
print("ERROR: No se generó ningún archivo de salida")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Tomar el primer archivo generado (debería ser único en modo simple)
|
||||||
|
generated_file = generated_files[0]
|
||||||
|
shutil.move(generated_file, dest_scl_path)
|
||||||
|
|
||||||
|
# Limpiar directorios temporales
|
||||||
|
shutil.rmtree(temp_output_dir, ignore_errors=True)
|
||||||
|
|
||||||
|
print(f"✓ Conversión completada exitosamente: {dest_scl_path}")
|
||||||
|
success = True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR inesperado durante la conversión: {e}", file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# 3. Si NO se indicó --plc-dir ⇒ modo ORQUESTADOR
|
||||||
# Detecta todos los PLC (subdirectorios con al menos un .xml) y lanza
|
# Detecta todos los PLC (subdirectorios con al menos un .xml) y lanza
|
||||||
# este mismo script para cada uno con el flag --plc-dir.
|
# este mismo script para cada uno con el flag --plc-dir.
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
if cli_args.plc_dir is None:
|
if cli_args.plc_dir is None:
|
||||||
if not working_directory or not os.path.isdir(working_directory):
|
if not working_directory or not os.path.isdir(working_directory):
|
||||||
print("Error: 'working_directory' inválido en la configuración.", file=sys.stderr)
|
print(
|
||||||
|
"Error: 'working_directory' inválido en la configuración.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Detectar PLCs como subdirectorios que contengan al menos un XML
|
# Detectar PLCs como subdirectorios que contengan al menos un XML
|
||||||
|
@ -307,50 +453,71 @@ if __name__ == "__main__":
|
||||||
# Ejecutar secuencialmente el script para cada PLC
|
# Ejecutar secuencialmente el script para cada PLC
|
||||||
overall_exit_code = 0
|
overall_exit_code = 0
|
||||||
for plc_dir in detected_plc_dirs:
|
for plc_dir in detected_plc_dirs:
|
||||||
print(f"\n=== Lanzando procesamiento para PLC: {os.path.basename(plc_dir)} ===")
|
print(
|
||||||
ret = subprocess.call([sys.executable, os.path.abspath(__file__), "--plc-dir", plc_dir])
|
f"\n=== Lanzando procesamiento para PLC: {os.path.basename(plc_dir)} ==="
|
||||||
|
)
|
||||||
|
ret = subprocess.call(
|
||||||
|
[sys.executable, os.path.abspath(__file__), "--plc-dir", plc_dir]
|
||||||
|
)
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
overall_exit_code = 1 # Registrar fallo global si algún PLC falla
|
overall_exit_code = 1 # Registrar fallo global si algún PLC falla
|
||||||
|
|
||||||
sys.exit(overall_exit_code)
|
sys.exit(overall_exit_code)
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# 3. Modo INTERNO (se recibió --plc-dir) ⇒ procesar sólo ese PLC
|
# 4. Modo INTERNO (se recibió --plc-dir) ⇒ procesar sólo ese PLC
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
xml_project_dir = os.path.abspath(cli_args.plc_dir)
|
xml_project_dir = os.path.abspath(cli_args.plc_dir)
|
||||||
if not os.path.isdir(xml_project_dir):
|
if not os.path.isdir(xml_project_dir):
|
||||||
print(f"Error: El directorio PLC especificado no existe: {xml_project_dir}", file=sys.stderr)
|
print(
|
||||||
|
f"Error: El directorio PLC especificado no existe: {xml_project_dir}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Usaremos el nombre del PLC para diferenciar los logs
|
# Usaremos el nombre del PLC para diferenciar los logs
|
||||||
plc_name_safe = os.path.basename(xml_project_dir.strip(os.sep))
|
plc_name_safe = os.path.basename(xml_project_dir.strip(os.sep))
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# 3.1 Leer parámetros específicos del grupo para reutilizarlos más abajo
|
# 4.1 Leer parámetros específicos del grupo para reutilizarlos más abajo
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
xml_parser_config = configs.get("level2", {})
|
xml_parser_config = configs.get("level2", {})
|
||||||
|
|
||||||
cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output")
|
cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output")
|
||||||
cfg_xref_output_dirname = xml_parser_config.get("xref_output_dir", "xref_output")
|
cfg_xref_output_dirname = xml_parser_config.get("xref_output_dir", "xref_output")
|
||||||
cfg_xref_source_subdir = xml_parser_config.get("xref_source_subdir", "source")
|
cfg_xref_source_subdir = xml_parser_config.get("xref_source_subdir", "source")
|
||||||
cfg_call_xref_filename = xml_parser_config.get("call_xref_filename", "xref_calls_tree.md")
|
cfg_call_xref_filename = xml_parser_config.get(
|
||||||
cfg_db_usage_xref_filename = xml_parser_config.get("db_usage_xref_filename", "xref_db_usage_summary.md")
|
"call_xref_filename", "xref_calls_tree.md"
|
||||||
cfg_plc_tag_xref_filename = xml_parser_config.get("plc_tag_xref_filename", "xref_plc_tags_summary.md")
|
)
|
||||||
|
cfg_db_usage_xref_filename = xml_parser_config.get(
|
||||||
|
"db_usage_xref_filename", "xref_db_usage_summary.md"
|
||||||
|
)
|
||||||
|
cfg_plc_tag_xref_filename = xml_parser_config.get(
|
||||||
|
"plc_tag_xref_filename", "xref_plc_tags_summary.md"
|
||||||
|
)
|
||||||
|
|
||||||
# Conversión de enteros con control de errores
|
# Conversión de enteros con control de errores
|
||||||
try:
|
try:
|
||||||
cfg_max_call_depth = int(xml_parser_config.get("max_call_depth", 5))
|
cfg_max_call_depth = int(xml_parser_config.get("max_call_depth", 5))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
print("Advertencia: Valor inválido para 'max_call_depth' en la configuración. Usando valor por defecto 5.", file=sys.stderr)
|
print(
|
||||||
|
"Advertencia: Valor inválido para 'max_call_depth' en la configuración. Usando valor por defecto 5.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
cfg_max_call_depth = 5
|
cfg_max_call_depth = 5
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cfg_max_users_list = int(xml_parser_config.get("max_users_list", 20))
|
cfg_max_users_list = int(xml_parser_config.get("max_users_list", 20))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
print("Advertencia: Valor inválido para 'max_users_list' en la configuración. Usando valor por defecto 20.", file=sys.stderr)
|
print(
|
||||||
|
"Advertencia: Valor inválido para 'max_users_list' en la configuración. Usando valor por defecto 20.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
cfg_max_users_list = 20
|
cfg_max_users_list = 20
|
||||||
|
|
||||||
cfg_aggregated_filename = xml_parser_config.get("aggregated_filename", "full_project_representation.md")
|
cfg_aggregated_filename = xml_parser_config.get(
|
||||||
|
"aggregated_filename", "full_project_representation.md"
|
||||||
|
)
|
||||||
|
|
||||||
# Generar un nombre de log específico por PLC
|
# Generar un nombre de log específico por PLC
|
||||||
log_filename_dynamic = f"log_{plc_name_safe}.txt"
|
log_filename_dynamic = f"log_{plc_name_safe}.txt"
|
||||||
|
@ -390,37 +557,59 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
xml_files_found.sort()
|
xml_files_found.sort()
|
||||||
[
|
[
|
||||||
log_message(f" - {os.path.relpath(xml_file, working_directory)}", log_f) # Mostrar ruta relativa al working_directory original
|
log_message(
|
||||||
|
f" - {os.path.relpath(xml_file, working_directory)}", log_f
|
||||||
|
) # Mostrar ruta relativa al working_directory original
|
||||||
for xml_file in xml_files_found
|
for xml_file in xml_files_found
|
||||||
]
|
]
|
||||||
|
|
||||||
# --- NUEVO: Identificar bloques SCL nativos ---
|
# --- NUEVO: Identificar bloques SCL nativos ---
|
||||||
log_message("\n--- Fase 0.5: Identificando archivos .scl nativos existentes ---", log_f)
|
log_message(
|
||||||
|
"\n--- Fase 0.5: Identificando archivos .scl nativos existentes ---", log_f
|
||||||
|
)
|
||||||
native_scl_blocks = set()
|
native_scl_blocks = set()
|
||||||
try:
|
try:
|
||||||
# Usar un patrón similar a la Fase 1.5 para encontrar SCLs en el proyecto fuente
|
# Usar un patrón similar a la Fase 1.5 para encontrar SCLs en el proyecto fuente
|
||||||
search_scl_pattern_native = os.path.join(xml_project_dir, "**", "*.scl")
|
search_scl_pattern_native = os.path.join(xml_project_dir, "**", "*.scl")
|
||||||
existing_scl_files_native = glob.glob(search_scl_pattern_native, recursive=True)
|
existing_scl_files_native = glob.glob(
|
||||||
|
search_scl_pattern_native, recursive=True
|
||||||
|
)
|
||||||
|
|
||||||
# Excluir directorios de salida para evitar auto-referencias si están anidados
|
# Excluir directorios de salida para evitar auto-referencias si están anidados
|
||||||
scl_output_dir_abs_native = os.path.abspath(os.path.join(xml_project_dir, cfg_scl_output_dirname))
|
scl_output_dir_abs_native = os.path.abspath(
|
||||||
xref_output_dir_abs_native = os.path.abspath(os.path.join(xml_project_dir, cfg_xref_output_dirname))
|
os.path.join(xml_project_dir, cfg_scl_output_dirname)
|
||||||
|
)
|
||||||
|
xref_output_dir_abs_native = os.path.abspath(
|
||||||
|
os.path.join(xml_project_dir, cfg_xref_output_dirname)
|
||||||
|
)
|
||||||
|
|
||||||
for scl_file_path in existing_scl_files_native:
|
for scl_file_path in existing_scl_files_native:
|
||||||
if not os.path.abspath(os.path.dirname(scl_file_path)).startswith(scl_output_dir_abs_native) and \
|
if not os.path.abspath(os.path.dirname(scl_file_path)).startswith(
|
||||||
not os.path.abspath(os.path.dirname(scl_file_path)).startswith(xref_output_dir_abs_native):
|
scl_output_dir_abs_native
|
||||||
|
) and not os.path.abspath(os.path.dirname(scl_file_path)).startswith(
|
||||||
|
xref_output_dir_abs_native
|
||||||
|
):
|
||||||
base_name = os.path.splitext(os.path.basename(scl_file_path))[0]
|
base_name = os.path.splitext(os.path.basename(scl_file_path))[0]
|
||||||
native_scl_blocks.add(base_name)
|
native_scl_blocks.add(base_name)
|
||||||
log_message(f"Se identificaron {len(native_scl_blocks)} posibles bloques SCL nativos (con archivo .scl).", log_f)
|
log_message(
|
||||||
|
f"Se identificaron {len(native_scl_blocks)} posibles bloques SCL nativos (con archivo .scl).",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_message(f"Error durante la identificación de SCL nativos: {e}. Se continuará sin priorización.", log_f)
|
log_message(
|
||||||
|
f"Error durante la identificación de SCL nativos: {e}. Se continuará sin priorización.",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
# --- FIN NUEVO ---
|
# --- FIN NUEVO ---
|
||||||
|
|
||||||
|
|
||||||
# --- Directorios de salida ---
|
# --- Directorios de salida ---
|
||||||
# Estos directorios ahora se crearán DENTRO de xml_project_dir (es decir, dentro de 'PLC')
|
# Estos directorios ahora se crearán DENTRO de xml_project_dir (es decir, dentro de 'PLC')
|
||||||
scl_output_dir = os.path.join(xml_project_dir, cfg_scl_output_dirname) # Usar valor de config
|
scl_output_dir = os.path.join(
|
||||||
xref_output_dir = os.path.join(xml_project_dir, cfg_xref_output_dirname) # Usar valor de config
|
xml_project_dir, cfg_scl_output_dirname
|
||||||
|
) # Usar valor de config
|
||||||
|
xref_output_dir = os.path.join(
|
||||||
|
xml_project_dir, cfg_xref_output_dirname
|
||||||
|
) # Usar valor de config
|
||||||
# <-- ADDED: Ensure output directories exist -->
|
# <-- ADDED: Ensure output directories exist -->
|
||||||
os.makedirs(scl_output_dir, exist_ok=True)
|
os.makedirs(scl_output_dir, exist_ok=True)
|
||||||
os.makedirs(xref_output_dir, exist_ok=True)
|
os.makedirs(xref_output_dir, exist_ok=True)
|
||||||
|
@ -448,7 +637,8 @@ if __name__ == "__main__":
|
||||||
os.makedirs(parsing_dir, exist_ok=True)
|
os.makedirs(parsing_dir, exist_ok=True)
|
||||||
json_output_file = os.path.join(parsing_dir, f"{base_filename}.json")
|
json_output_file = os.path.join(parsing_dir, f"{base_filename}.json")
|
||||||
processed_json_filepath = os.path.join(
|
processed_json_filepath = os.path.join(
|
||||||
parsing_dir, f"{base_filename}_processed.json" # <-- Corregido: nombre correcto
|
parsing_dir,
|
||||||
|
f"{base_filename}_processed.json", # <-- Corregido: nombre correcto
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- NUEVO: Comprobar si es un SCL nativo ---
|
# --- NUEVO: Comprobar si es un SCL nativo ---
|
||||||
|
@ -489,11 +679,16 @@ if __name__ == "__main__":
|
||||||
success_x1 = True # Asumir éxito si se salta
|
success_x1 = True # Asumir éxito si se salta
|
||||||
else:
|
else:
|
||||||
log_message(
|
log_message(
|
||||||
f"--- Ejecutando x1 (convert_xml_to_json) para: {relative_path} ---", log_f
|
f"--- Ejecutando x1 (convert_xml_to_json) para: {relative_path} ---",
|
||||||
|
log_f,
|
||||||
)
|
)
|
||||||
success_x1 = convert_xml_to_json(xml_filepath, json_output_file)
|
success_x1 = convert_xml_to_json(xml_filepath, json_output_file)
|
||||||
if not success_x1:
|
if not success_x1:
|
||||||
log_message(f"--- x1 FALLÓ para: {relative_path} ---", log_f, also_print=False) # La función ya imprime el error
|
log_message(
|
||||||
|
f"--- x1 FALLÓ para: {relative_path} ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
) # La función ya imprime el error
|
||||||
|
|
||||||
if not success_x1:
|
if not success_x1:
|
||||||
failed_count += 1
|
failed_count += 1
|
||||||
|
@ -507,11 +702,18 @@ if __name__ == "__main__":
|
||||||
success_x2 = True # Asumir éxito si se salta
|
success_x2 = True # Asumir éxito si se salta
|
||||||
else:
|
else:
|
||||||
log_message(
|
log_message(
|
||||||
f"--- Ejecutando x2 (process_json_to_scl) para: {relative_path} ---", log_f
|
f"--- Ejecutando x2 (process_json_to_scl) para: {relative_path} ---",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
|
success_x2 = process_json_to_scl(
|
||||||
|
json_output_file, processed_json_filepath
|
||||||
)
|
)
|
||||||
success_x2 = process_json_to_scl(json_output_file, processed_json_filepath)
|
|
||||||
if not success_x2:
|
if not success_x2:
|
||||||
log_message(f"--- x2 FALLÓ para: {relative_path} ---", log_f, also_print=False)
|
log_message(
|
||||||
|
f"--- x2 FALLÓ para: {relative_path} ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
|
|
||||||
if not success_x2:
|
if not success_x2:
|
||||||
failed_count += 1
|
failed_count += 1
|
||||||
|
@ -523,7 +725,8 @@ if __name__ == "__main__":
|
||||||
skipped_partial_count += 1 # Se saltó x1/x2 pero se ejecuta x3
|
skipped_partial_count += 1 # Se saltó x1/x2 pero se ejecuta x3
|
||||||
|
|
||||||
log_message(
|
log_message(
|
||||||
f"--- Ejecutando x3 (generate_scl_or_markdown) para: {relative_path} ---", log_f
|
f"--- Ejecutando x3 (generate_scl_or_markdown) para: {relative_path} ---",
|
||||||
|
log_f,
|
||||||
)
|
)
|
||||||
# Asegurar que el directorio de salida final exista ANTES de llamar a la función
|
# Asegurar que el directorio de salida final exista ANTES de llamar a la función
|
||||||
os.makedirs(scl_output_dir, exist_ok=True)
|
os.makedirs(scl_output_dir, exist_ok=True)
|
||||||
|
@ -531,7 +734,11 @@ if __name__ == "__main__":
|
||||||
processed_json_filepath, scl_output_dir, xml_project_dir
|
processed_json_filepath, scl_output_dir, xml_project_dir
|
||||||
)
|
)
|
||||||
if not success_x3:
|
if not success_x3:
|
||||||
log_message(f"--- x3 FALLÓ para: {relative_path} ---", log_f, also_print=False)
|
log_message(
|
||||||
|
f"--- x3 FALLÓ para: {relative_path} ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
failed_count += 1
|
failed_count += 1
|
||||||
continue # No continuar si x3 falló
|
continue # No continuar si x3 falló
|
||||||
|
|
||||||
|
@ -540,8 +747,15 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Capturar cualquier error inesperado durante las llamadas a funciones
|
# Capturar cualquier error inesperado durante las llamadas a funciones
|
||||||
log_message(f"--- ERROR INESPERADO procesando {relative_path}: {e} ---", log_f, also_print=False)
|
log_message(
|
||||||
print(f"--- ERROR INESPERADO procesando {relative_path}: {e} ---", file=sys.stderr)
|
f"--- ERROR INESPERADO procesando {relative_path}: {e} ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"--- ERROR INESPERADO procesando {relative_path}: {e} ---",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
traceback_str = traceback.format_exc()
|
traceback_str = traceback.format_exc()
|
||||||
log_message(traceback_str, log_f, also_print=False) # Loguear traceback
|
log_message(traceback_str, log_f, also_print=False) # Loguear traceback
|
||||||
traceback.print_exc(file=sys.stderr) # Mostrar traceback en consola
|
traceback.print_exc(file=sys.stderr) # Mostrar traceback en consola
|
||||||
|
@ -549,7 +763,10 @@ if __name__ == "__main__":
|
||||||
continue # Pasar al siguiente archivo
|
continue # Pasar al siguiente archivo
|
||||||
|
|
||||||
# <-- ADDED: Phase 1.5: Copy existing SCL files -->
|
# <-- ADDED: Phase 1.5: Copy existing SCL files -->
|
||||||
log_message(f"\n--- Fase 1.5: Copiando archivos SCL existentes desde '{xml_project_dir}' a '{scl_output_dir}' ---", log_f)
|
log_message(
|
||||||
|
f"\n--- Fase 1.5: Copiando archivos SCL existentes desde '{xml_project_dir}' a '{scl_output_dir}' ---",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
copied_scl_count = 0
|
copied_scl_count = 0
|
||||||
skipped_scl_count = 0
|
skipped_scl_count = 0
|
||||||
try:
|
try:
|
||||||
|
@ -561,32 +778,61 @@ if __name__ == "__main__":
|
||||||
xref_output_dir_abs = os.path.abspath(xref_output_dir)
|
xref_output_dir_abs = os.path.abspath(xref_output_dir)
|
||||||
|
|
||||||
filtered_scl_files = [
|
filtered_scl_files = [
|
||||||
f for f in existing_scl_files
|
f
|
||||||
if not os.path.abspath(os.path.dirname(f)).startswith(scl_output_dir_abs) and \
|
for f in existing_scl_files
|
||||||
not os.path.abspath(os.path.dirname(f)).startswith(xref_output_dir_abs)
|
if not os.path.abspath(os.path.dirname(f)).startswith(
|
||||||
|
scl_output_dir_abs
|
||||||
|
)
|
||||||
|
and not os.path.abspath(os.path.dirname(f)).startswith(
|
||||||
|
xref_output_dir_abs
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
if not filtered_scl_files:
|
if not filtered_scl_files:
|
||||||
log_message("No se encontraron archivos .scl existentes para copiar (excluyendo directorios de salida).", log_f)
|
log_message(
|
||||||
|
"No se encontraron archivos .scl existentes para copiar (excluyendo directorios de salida).",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
log_message(f"Se encontraron {len(filtered_scl_files)} archivos .scl existentes para copiar:", log_f)
|
log_message(
|
||||||
|
f"Se encontraron {len(filtered_scl_files)} archivos .scl existentes para copiar:",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
for src_scl_path in filtered_scl_files:
|
for src_scl_path in filtered_scl_files:
|
||||||
relative_scl_path = os.path.relpath(src_scl_path, xml_project_dir)
|
relative_scl_path = os.path.relpath(src_scl_path, xml_project_dir)
|
||||||
dest_scl_path = os.path.join(scl_output_dir, os.path.basename(src_scl_path)) # Copia directa al scl_output del PLC
|
dest_scl_path = os.path.join(
|
||||||
|
scl_output_dir, os.path.basename(src_scl_path)
|
||||||
|
) # Copia directa al scl_output del PLC
|
||||||
|
|
||||||
# Check if a file with the same name was already generated from XML
|
# Check if a file with the same name was already generated from XML
|
||||||
if os.path.exists(dest_scl_path):
|
if os.path.exists(dest_scl_path):
|
||||||
log_message(f" - Omitiendo copia de '{relative_scl_path}': Ya existe un archivo generado con el mismo nombre en el destino.", log_f, also_print=False)
|
log_message(
|
||||||
|
f" - Omitiendo copia de '{relative_scl_path}': Ya existe un archivo generado con el mismo nombre en el destino.",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
skipped_scl_count += 1
|
skipped_scl_count += 1
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
log_message(f" - Copiando '{relative_scl_path}' a '{os.path.relpath(dest_scl_path, working_directory)}'", log_f, also_print=False)
|
log_message(
|
||||||
shutil.copy2(src_scl_path, dest_scl_path) # copy2 preserves metadata
|
f" - Copiando '{relative_scl_path}' a '{os.path.relpath(dest_scl_path, working_directory)}'",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
|
shutil.copy2(
|
||||||
|
src_scl_path, dest_scl_path
|
||||||
|
) # copy2 preserves metadata
|
||||||
copied_scl_count += 1
|
copied_scl_count += 1
|
||||||
except Exception as copy_err:
|
except Exception as copy_err:
|
||||||
log_message(f" - ERROR copiando '{relative_scl_path}': {copy_err}", log_f)
|
log_message(
|
||||||
|
f" - ERROR copiando '{relative_scl_path}': {copy_err}",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
# Decide if this should count as a general failure
|
# Decide if this should count as a general failure
|
||||||
log_message(f"Copia de SCL existentes finalizada. Copiados: {copied_scl_count}, Omitidos (conflicto nombre): {skipped_scl_count}", log_f)
|
log_message(
|
||||||
|
f"Copia de SCL existentes finalizada. Copiados: {copied_scl_count}, Omitidos (conflicto nombre): {skipped_scl_count}",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_message(f"Error durante la Fase 1.5 (Copia SCL): {e}", log_f)
|
log_message(f"Error durante la Fase 1.5 (Copia SCL): {e}", log_f)
|
||||||
|
@ -629,13 +875,22 @@ if __name__ == "__main__":
|
||||||
cfg_db_usage_xref_filename,
|
cfg_db_usage_xref_filename,
|
||||||
cfg_plc_tag_xref_filename,
|
cfg_plc_tag_xref_filename,
|
||||||
cfg_max_call_depth,
|
cfg_max_call_depth,
|
||||||
cfg_max_users_list)
|
cfg_max_users_list,
|
||||||
|
)
|
||||||
if not success_x4:
|
if not success_x4:
|
||||||
# La función interna ya debería haber impreso/logueado el error específico
|
# La función interna ya debería haber impreso/logueado el error específico
|
||||||
log_message(f"--- x4 (generate_cross_references) FALLÓ. ---", log_f, also_print=False)
|
log_message(
|
||||||
|
f"--- x4 (generate_cross_references) FALLÓ. ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Capturar error inesperado en la llamada a x4
|
# Capturar error inesperado en la llamada a x4
|
||||||
log_message(f"--- ERROR INESPERADO ejecutando x4: {e} ---", log_f, also_print=False)
|
log_message(
|
||||||
|
f"--- ERROR INESPERADO ejecutando x4: {e} ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
print(f"--- ERROR INESPERADO ejecutando x4: {e} ---", file=sys.stderr)
|
print(f"--- ERROR INESPERADO ejecutando x4: {e} ---", file=sys.stderr)
|
||||||
traceback_str = traceback.format_exc()
|
traceback_str = traceback.format_exc()
|
||||||
log_message(traceback_str, log_f, also_print=False)
|
log_message(traceback_str, log_f, also_print=False)
|
||||||
|
@ -647,7 +902,7 @@ if __name__ == "__main__":
|
||||||
# --- PARTE 4: EJECUTAR x5 (Agregación) ---
|
# --- PARTE 4: EJECUTAR x5 (Agregación) ---
|
||||||
log_message(
|
log_message(
|
||||||
f"\n--- Fase 3: Ejecutando x5_aggregate.py (salida en '{cfg_aggregated_filename}') ---", # Usar valor de config
|
f"\n--- Fase 3: Ejecutando x5_aggregate.py (salida en '{cfg_aggregated_filename}') ---", # Usar valor de config
|
||||||
log_f
|
log_f,
|
||||||
)
|
)
|
||||||
run_x5 = True
|
run_x5 = True
|
||||||
success_x5 = False
|
success_x5 = False
|
||||||
|
@ -655,7 +910,8 @@ if __name__ == "__main__":
|
||||||
can_run_x5 = failed_count < len(xml_files_found)
|
can_run_x5 = failed_count < len(xml_files_found)
|
||||||
if not can_run_x5 and len(xml_files_found) > 0:
|
if not can_run_x5 and len(xml_files_found) > 0:
|
||||||
log_message(
|
log_message(
|
||||||
"Advertencia: Todos los archivos fallaron en x1/x2/x3. Saltando x5.", log_f
|
"Advertencia: Todos los archivos fallaron en x1/x2/x3. Saltando x5.",
|
||||||
|
log_f,
|
||||||
)
|
)
|
||||||
run_x5 = False
|
run_x5 = False
|
||||||
elif len(xml_files_found) == 0:
|
elif len(xml_files_found) == 0:
|
||||||
|
@ -666,7 +922,7 @@ if __name__ == "__main__":
|
||||||
output_agg_file = os.path.join(xml_project_dir, cfg_aggregated_filename)
|
output_agg_file = os.path.join(xml_project_dir, cfg_aggregated_filename)
|
||||||
log_message(
|
log_message(
|
||||||
f"Ejecutando x5 (aggregate_outputs) sobre: {xml_project_dir}, salida agregada en: {output_agg_file}",
|
f"Ejecutando x5 (aggregate_outputs) sobre: {xml_project_dir}, salida agregada en: {output_agg_file}",
|
||||||
log_f
|
log_f,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
# Llamada directa a la función de x5
|
# Llamada directa a la función de x5
|
||||||
|
@ -675,13 +931,22 @@ if __name__ == "__main__":
|
||||||
xml_project_dir,
|
xml_project_dir,
|
||||||
output_agg_file,
|
output_agg_file,
|
||||||
cfg_scl_output_dirname,
|
cfg_scl_output_dirname,
|
||||||
cfg_xref_output_dirname)
|
cfg_xref_output_dirname,
|
||||||
|
)
|
||||||
if not success_x5:
|
if not success_x5:
|
||||||
# La función interna ya debería haber impreso/logueado el error específico
|
# La función interna ya debería haber impreso/logueado el error específico
|
||||||
log_message(f"--- x5 (aggregate_outputs) FALLÓ. ---", log_f, also_print=False)
|
log_message(
|
||||||
|
f"--- x5 (aggregate_outputs) FALLÓ. ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Capturar error inesperado en la llamada a x5
|
# Capturar error inesperado en la llamada a x5
|
||||||
log_message(f"--- ERROR INESPERADO ejecutando x5: {e} ---", log_f, also_print=False)
|
log_message(
|
||||||
|
f"--- ERROR INESPERADO ejecutando x5: {e} ---",
|
||||||
|
log_f,
|
||||||
|
also_print=False,
|
||||||
|
)
|
||||||
print(f"--- ERROR INESPERADO ejecutando x5: {e} ---", file=sys.stderr)
|
print(f"--- ERROR INESPERADO ejecutando x5: {e} ---", file=sys.stderr)
|
||||||
traceback_str = traceback.format_exc()
|
traceback_str = traceback.format_exc()
|
||||||
log_message(traceback_str, log_f, also_print=False)
|
log_message(traceback_str, log_f, also_print=False)
|
||||||
|
@ -708,13 +973,21 @@ if __name__ == "__main__":
|
||||||
f"Archivos parcialmente saltados (x1, x2 saltados; x3 ejecutado): {skipped_partial_count}",
|
f"Archivos parcialmente saltados (x1, x2 saltados; x3 ejecutado): {skipped_partial_count}",
|
||||||
log_f,
|
log_f,
|
||||||
)
|
)
|
||||||
log_message(f"Archivos fallidos (en x1, x2, x3 o error inesperado): {failed_count}", log_f)
|
log_message(
|
||||||
|
f"Archivos fallidos (en x1, x2, x3 o error inesperado): {failed_count}",
|
||||||
|
log_f,
|
||||||
|
)
|
||||||
log_message( # <-- NUEVO: Reportar SCL nativos saltados
|
log_message( # <-- NUEVO: Reportar SCL nativos saltados
|
||||||
f"Archivos XML omitidos (priorizando .scl nativo): {skipped_for_native_scl}",
|
f"Archivos XML omitidos (priorizando .scl nativo): {skipped_for_native_scl}",
|
||||||
log_f,
|
log_f,
|
||||||
)
|
)
|
||||||
log_message(f"Archivos SCL existentes copiados (Fase 1.5): {copied_scl_count}", log_f) # <-- ADDED: Report copied SCL
|
log_message(
|
||||||
log_message(f"Archivos SCL existentes omitidos por conflicto (Fase 1.5): {skipped_scl_count}", log_f) # <-- ADDED: Report skipped SCL
|
f"Archivos SCL existentes copiados (Fase 1.5): {copied_scl_count}", log_f
|
||||||
|
) # <-- ADDED: Report copied SCL
|
||||||
|
log_message(
|
||||||
|
f"Archivos SCL existentes omitidos por conflicto (Fase 1.5): {skipped_scl_count}",
|
||||||
|
log_f,
|
||||||
|
) # <-- ADDED: Report skipped SCL
|
||||||
log_message(
|
log_message(
|
||||||
f"Fase 2 (Generación XRef - x4): {'Completada' if run_x4 and success_x4 else ('Fallida' if run_x4 and not success_x4 else 'Omitida')}",
|
f"Fase 2 (Generación XRef - x4): {'Completada' if run_x4 and success_x4 else ('Fallida' if run_x4 and not success_x4 else 'Omitida')}",
|
||||||
log_f,
|
log_f,
|
||||||
|
@ -742,14 +1015,19 @@ if __name__ == "__main__":
|
||||||
print(
|
print(
|
||||||
f"\n{final_console_message} Consulta '{log_filename_dynamic}' para detalles."
|
f"\n{final_console_message} Consulta '{log_filename_dynamic}' para detalles."
|
||||||
) # Mostrar mensaje en consola
|
) # Mostrar mensaje en consola
|
||||||
log_message("="*41 + " LOG END " + "="*42, log_f)
|
log_message("=" * 41 + " LOG END " + "=" * 42, log_f)
|
||||||
|
|
||||||
# <-- NUEVO: Flush explícito antes de salir -->
|
# <-- NUEVO: Flush explícito antes de salir -->
|
||||||
try:
|
try:
|
||||||
log_f.flush()
|
log_f.flush()
|
||||||
os.fsync(log_f.fileno()) # Intenta forzar escritura a disco (puede no funcionar en todos los OS)
|
os.fsync(
|
||||||
|
log_f.fileno()
|
||||||
|
) # Intenta forzar escritura a disco (puede no funcionar en todos los OS)
|
||||||
except Exception as flush_err:
|
except Exception as flush_err:
|
||||||
print(f"Advertencia: Error durante flush/fsync final del log: {flush_err}", file=sys.stderr)
|
print(
|
||||||
|
f"Advertencia: Error durante flush/fsync final del log: {flush_err}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
# <-- FIN NUEVO -->
|
# <-- FIN NUEVO -->
|
||||||
|
|
||||||
# Mensaje final ya impreso antes del flush
|
# Mensaje final ya impreso antes del flush
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
"""
|
||||||
|
x8_manual_gui.py - Wrapper Simple para XML→SCL
|
||||||
|
|
||||||
|
Este script es un wrapper simple que:
|
||||||
|
1. Abre un cuadro de diálogo para seleccionar archivo XML
|
||||||
|
2. Abre un cuadro de diálogo para seleccionar directorio de destino
|
||||||
|
3. Ejecuta automáticamente x0_main.py en modo simple
|
||||||
|
|
||||||
|
No requiere GUI compleja, solo usa los cuadros de diálogo nativos de Windows.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog, messagebox
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Función principal - Solo cuadros de diálogo y ejecución"""
|
||||||
|
|
||||||
|
# Configurar el directorio de script
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
x0_main_path = os.path.join(script_dir, "x0_main.py")
|
||||||
|
|
||||||
|
# Verificar que x0_main.py existe
|
||||||
|
if not os.path.exists(x0_main_path):
|
||||||
|
print(f"Error: No se encontró x0_main.py en: {x0_main_path}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("=== XML -> SCL Converter ===")
|
||||||
|
print("Selecciona el archivo XML y directorio de destino...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Crear ventana oculta para los cuadros de diálogo
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw() # Ocultar la ventana principal
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. Seleccionar archivo XML
|
||||||
|
print("1. Seleccionando archivo XML...")
|
||||||
|
source_xml = filedialog.askopenfilename(
|
||||||
|
title="Seleccionar archivo XML de Siemens TIA Portal",
|
||||||
|
filetypes=[("Archivos XML", "*.xml"), ("Todos los archivos", "*.*")],
|
||||||
|
initialdir=script_dir,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not source_xml:
|
||||||
|
print("Operación cancelada por el usuario.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
print(f" Archivo seleccionado: {os.path.basename(source_xml)}")
|
||||||
|
|
||||||
|
# 2. Seleccionar directorio de destino
|
||||||
|
print("2. Seleccionando directorio de destino...")
|
||||||
|
dest_dir = filedialog.askdirectory(
|
||||||
|
title="Seleccionar directorio de destino", initialdir=script_dir
|
||||||
|
)
|
||||||
|
|
||||||
|
if not dest_dir:
|
||||||
|
print("Operación cancelada por el usuario.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
print(f" Directorio seleccionado: {dest_dir}")
|
||||||
|
|
||||||
|
# 3. Generar nombre de archivo de salida
|
||||||
|
base_name = os.path.splitext(os.path.basename(source_xml))[0]
|
||||||
|
dest_filename = f"{base_name}.scl"
|
||||||
|
dest_scl = os.path.join(dest_dir, dest_filename)
|
||||||
|
|
||||||
|
print(f"3. Archivo de salida: {dest_filename}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 4. Confirmar operación
|
||||||
|
confirm = messagebox.askyesno(
|
||||||
|
"Confirmar Conversión",
|
||||||
|
f"¿Convertir el archivo?\n\n"
|
||||||
|
f"Origen: {os.path.basename(source_xml)}\n"
|
||||||
|
f"Destino: {dest_scl}\n\n"
|
||||||
|
f"¿Continuar?",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not confirm:
|
||||||
|
print("Operación cancelada por el usuario.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# 5. Ejecutar conversión
|
||||||
|
print("4. Ejecutando conversión...")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
sys.executable,
|
||||||
|
x0_main_path,
|
||||||
|
"--source-xml",
|
||||||
|
source_xml,
|
||||||
|
"--dest-scl",
|
||||||
|
dest_scl,
|
||||||
|
]
|
||||||
|
|
||||||
|
# Ejecutar proceso
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
cwd=script_dir,
|
||||||
|
capture_output=False, # Mostrar salida en tiempo real
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 6. Verificar resultado
|
||||||
|
print("=" * 50)
|
||||||
|
if result.returncode == 0 and os.path.exists(dest_scl):
|
||||||
|
print("✅ CONVERSIÓN COMPLETADA EXITOSAMENTE")
|
||||||
|
print(f"📁 Archivo generado: {dest_scl}")
|
||||||
|
|
||||||
|
# Preguntar si abrir el directorio
|
||||||
|
open_dir = messagebox.askyesno(
|
||||||
|
"Conversión Exitosa",
|
||||||
|
f"La conversión se completó exitosamente.\n\n"
|
||||||
|
f"Archivo generado:\n{dest_scl}\n\n"
|
||||||
|
f"¿Deseas abrir el directorio de destino?",
|
||||||
|
)
|
||||||
|
|
||||||
|
if open_dir:
|
||||||
|
os.startfile(dest_dir)
|
||||||
|
else:
|
||||||
|
print("❌ ERROR EN LA CONVERSIÓN")
|
||||||
|
print("Revisa los mensajes de error arriba.")
|
||||||
|
|
||||||
|
messagebox.showerror(
|
||||||
|
"Error en Conversión",
|
||||||
|
"La conversión falló. Revisa los mensajes de error en la consola.",
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ ERROR INESPERADO: {e}")
|
||||||
|
messagebox.showerror(
|
||||||
|
"Error Inesperado", f"Error inesperado durante la conversión:\n{e}"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cerrar la ventana oculta
|
||||||
|
root.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
14938
data/log.txt
14938
data/log.txt
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue