Implement SyrBrix Autocorrection Function Block and Syrup Line MFM Preparation Logic
- Added the SyrBrix Autocorrection function block (FB1809) to handle syrup brix and density measurements for sugar-based beverages. - Implemented logic for syrup autocorrection requests, latching, and running states. - Introduced a new function block for Syrup Line MFM Preparation (FB1813) to manage syrup line preparation and related timers. - Enhanced network logic for syrup preparation, including handling of manual drain and fuzzy logic for syrup density checks. - Updated variable handling and added necessary comments for clarity and maintainability.
This commit is contained in:
parent
b1ee3a0eae
commit
c907112293
|
@ -4,3 +4,127 @@ Para generar un resultado directo desde un xml a 1 scl
|
||||||
```bash
|
```bash
|
||||||
C:/Users/migue/miniconda3/envs/tia_scripting/python.exe "d:/Proyectos/Scripts/ParamManagerScripts/backend/script_groups/XML Parser to SCL/x0_main.py" --plc-dir "D:\Trabajo\VM\45 - HENKEL - VM Auto Changeover\ExportTia" --source-xml "D:\Trabajo\VM\45 - HENKEL - VM Auto Changeover\ExportTia\PLC_TL27_Q1\ProgramBlocks_XML\FB HMI Interlock.xml" --dest-scl "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\XML Parser to SCL\.example\FB_HMI_Interlock.scl"
|
C:/Users/migue/miniconda3/envs/tia_scripting/python.exe "d:/Proyectos/Scripts/ParamManagerScripts/backend/script_groups/XML Parser to SCL/x0_main.py" --plc-dir "D:\Trabajo\VM\45 - HENKEL - VM Auto Changeover\ExportTia" --source-xml "D:\Trabajo\VM\45 - HENKEL - VM Auto Changeover\ExportTia\PLC_TL27_Q1\ProgramBlocks_XML\FB HMI Interlock.xml" --dest-scl "D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\XML Parser to SCL\.example\FB_HMI_Interlock.scl"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Flujo de Trabajo para Resolución de Errores de Conversión
|
||||||
|
|
||||||
|
### 1. Identificación de Errores
|
||||||
|
|
||||||
|
**Comando para buscar errores en SCL generados:**
|
||||||
|
```bash
|
||||||
|
# Buscar TODOs sin implementar
|
||||||
|
grep -r "TODO:" *.scl
|
||||||
|
|
||||||
|
# Buscar líneas duplicadas P_TRIG
|
||||||
|
grep -r "P_TRIG.*- Mem:" *.scl
|
||||||
|
|
||||||
|
# Buscar acceso directo a memoria
|
||||||
|
grep -r "%DB[0-9]*\.DBX[0-9]*" *.scl
|
||||||
|
|
||||||
|
# Buscar instancias no declaradas
|
||||||
|
grep -r "#.*_INSTANCE_.*(" *.scl
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Categorización de Errores Comunes
|
||||||
|
|
||||||
|
#### **A. Errores de Edge Detection (P_TRIG/N_TRIG)**
|
||||||
|
- **Síntoma**: Líneas duplicadas con comentarios `// P_TRIG(...) - Mem: "variable"`
|
||||||
|
- **Causa**: El procesador de Coils genera tanto la asignación como el comentario
|
||||||
|
- **Solución**: Crear procesador específico para edge detection o mejorar process_coil.py
|
||||||
|
|
||||||
|
#### **B. Instancias de Timer No Declaradas**
|
||||||
|
- **Síntoma**: `#TP_INSTANCE_X(...); // TODO: Declarar #TP_INSTANCE_X : TP;`
|
||||||
|
- **Causa**: Los timers temporales no se declaran automáticamente en VAR_TEMP
|
||||||
|
- **Solución**: Mejorar process_timer.py para auto-declarar instancias temporales
|
||||||
|
|
||||||
|
#### **C. Acceso Directo a Memoria**
|
||||||
|
- **Síntoma**: `%DB960.DBX56.1 := ...`
|
||||||
|
- **Causa**: El symbol_manager no resuelve direcciones absolutas a variables simbólicas
|
||||||
|
- **Solución**: Mejorar symbol_manager.py para mapear direcciones absolutas
|
||||||
|
|
||||||
|
#### **D. Lógica Agrupada Incorrecta**
|
||||||
|
- **Síntoma**: Lógica compleja en una sola línea, difícil de leer
|
||||||
|
- **Causa**: El agrupador de IFs es demasiado agresivo
|
||||||
|
- **Solución**: Ajustar process_group_ifs en x2_process.py
|
||||||
|
|
||||||
|
### 3. Metodología de Corrección
|
||||||
|
|
||||||
|
#### **Paso 1: Análisis de Archivos SCL Problemáticos**
|
||||||
|
```bash
|
||||||
|
# Revisar archivo específico
|
||||||
|
python x0_main.py --source-xml "path/to/file.xml" --dest-scl "output.scl"
|
||||||
|
# Examinar output.scl para identificar patrones de error
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **Paso 2: Identificar el Procesador Responsable**
|
||||||
|
- **Coils**: `processors/process_coil.py` - Para asignaciones y edge detection
|
||||||
|
- **Timers**: `processors/process_timer.py` - Para TON, TOF, TP
|
||||||
|
- **Contacts**: `processors/process_contact.py` - Para lectura de variables
|
||||||
|
- **Direcciones de memoria**: `processors/symbol_manager.py` - Para resolución simbólica
|
||||||
|
|
||||||
|
#### **Paso 3: Implementar Corrección**
|
||||||
|
1. **Crear nuevo procesador** (si es necesario):
|
||||||
|
```python
|
||||||
|
# processors/process_ptrig.py
|
||||||
|
def get_processor_info():
|
||||||
|
return {
|
||||||
|
"type_name": "ptrig",
|
||||||
|
"processor_func": process_ptrig_instruction,
|
||||||
|
"priority": 5 # Ejecutar antes que Coils
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Mejorar procesador existente**:
|
||||||
|
- Agregar lógica específica para el caso problemático
|
||||||
|
- Actualizar manejo de dependencias
|
||||||
|
- Mejorar almacenamiento en sympy_map
|
||||||
|
|
||||||
|
#### **Paso 4: Validación**
|
||||||
|
```bash
|
||||||
|
# Re-ejecutar conversión
|
||||||
|
python x0_main.py --source-xml "problema.xml" --dest-scl "test.scl"
|
||||||
|
|
||||||
|
# Verificar que el error se resolvió
|
||||||
|
grep -c "TODO:" test.scl # Debe ser 0
|
||||||
|
grep -c "P_TRIG.*- Mem:" test.scl # Debe ser 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Patrones de Testing
|
||||||
|
|
||||||
|
#### **A. Testing Incremental**
|
||||||
|
```bash
|
||||||
|
# Test con archivo pequeño conocido
|
||||||
|
python x0_main.py --source-xml "simple_test.xml" --dest-scl "simple_out.scl"
|
||||||
|
|
||||||
|
# Test con archivo complejo original
|
||||||
|
python x0_main.py --source-xml "complex_original.xml" --dest-scl "complex_out.scl"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **B. Comparación de Resultados**
|
||||||
|
```bash
|
||||||
|
# Comparar antes/después
|
||||||
|
diff old_output.scl new_output.scl
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Herramientas de Debugging
|
||||||
|
|
||||||
|
#### **A. Activar Debug en x2_process.py**
|
||||||
|
```python
|
||||||
|
# Agregar prints de debug en procesadores específicos
|
||||||
|
print(f"DEBUG: Processing {instr_type} - UID: {instr_uid}")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **B. Revisar Logs de Conversión**
|
||||||
|
```bash
|
||||||
|
# Buscar patrones en logs
|
||||||
|
grep "ERROR\|WARNING\|TODO" log_*.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Checklist de Calidad
|
||||||
|
|
||||||
|
Antes de considerar un error "resuelto":
|
||||||
|
- [ ] No hay comentarios TODO en el SCL
|
||||||
|
- [ ] No hay líneas duplicadas de P_TRIG
|
||||||
|
- [ ] No hay acceso directo a memoria (%DB.DBX)
|
||||||
|
- [ ] Todas las variables de timer están declaradas
|
||||||
|
- [ ] El código SCL es sintácticamente válido
|
||||||
|
- [ ] La lógica funcional es equivalente al LAD original
|
|
@ -160,7 +160,21 @@ def _generate_scl_temp_vars(data, declared_temps):
|
||||||
scl_output.append("VAR_TEMP") # Only add if no temps were declared before
|
scl_output.append("VAR_TEMP") # Only add if no temps were declared before
|
||||||
for temp_name in additional_temps:
|
for temp_name in additional_temps:
|
||||||
scl_name = format_variable_name(temp_name)
|
scl_name = format_variable_name(temp_name)
|
||||||
inferred_type = "Bool"
|
# ENHANCED: Infer correct type based on variable name pattern
|
||||||
|
inferred_type = "Bool" # Default
|
||||||
|
if "_INSTANCE_" in temp_name:
|
||||||
|
if "TP_INSTANCE_" in temp_name:
|
||||||
|
inferred_type = "TP"
|
||||||
|
elif "TON_INSTANCE_" in temp_name:
|
||||||
|
inferred_type = "TON"
|
||||||
|
elif "TOF_INSTANCE_" in temp_name:
|
||||||
|
inferred_type = "TOF"
|
||||||
|
elif "CTU_INSTANCE_" in temp_name:
|
||||||
|
inferred_type = "CTU"
|
||||||
|
elif "CTD_INSTANCE_" in temp_name:
|
||||||
|
inferred_type = "CTD"
|
||||||
|
elif "CTUD_INSTANCE_" in temp_name:
|
||||||
|
inferred_type = "CTUD"
|
||||||
scl_output.append(
|
scl_output.append(
|
||||||
f" {scl_name} : {inferred_type}; // Auto-generated temporary"
|
f" {scl_name} : {inferred_type}; // Auto-generated temporary"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
Manejador de UIDs duplicados en el JSON
|
Manejador de UIDs duplicados en el JSON
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def detect_and_resolve_duplicate_uids(data):
|
def detect_and_resolve_duplicate_uids(data):
|
||||||
"""
|
"""
|
||||||
Detecta y resuelve UIDs duplicados en el JSON de datos.
|
Detecta y resuelve UIDs duplicados en el JSON de datos.
|
||||||
|
@ -26,7 +27,9 @@ def detect_and_resolve_duplicate_uids(data):
|
||||||
# Segunda pasada: renombrar duplicados
|
# Segunda pasada: renombrar duplicados
|
||||||
for uid, instances in uid_counts.items():
|
for uid, instances in uid_counts.items():
|
||||||
if len(instances) > 1:
|
if len(instances) > 1:
|
||||||
print(f"INFO: UID duplicado encontrado: {uid} ({len(instances)} instancias)")
|
print(
|
||||||
|
f"INFO: UID duplicado encontrado: {uid} ({len(instances)} instancias)"
|
||||||
|
)
|
||||||
|
|
||||||
# Mantener la primera instancia, renombrar las demás
|
# Mantener la primera instancia, renombrar las demás
|
||||||
for i, (network_id, instruction) in enumerate(instances[1:], 1):
|
for i, (network_id, instruction) in enumerate(instances[1:], 1):
|
||||||
|
@ -47,6 +50,7 @@ def detect_and_resolve_duplicate_uids(data):
|
||||||
|
|
||||||
return modifications_made > 0
|
return modifications_made > 0
|
||||||
|
|
||||||
|
|
||||||
def update_uid_references(data, old_uid, new_uid, target_network_id):
|
def update_uid_references(data, old_uid, new_uid, target_network_id):
|
||||||
"""
|
"""
|
||||||
Actualiza las referencias al UID antiguo en conexiones de otras instrucciones
|
Actualiza las referencias al UID antiguo en conexiones de otras instrucciones
|
||||||
|
@ -62,4 +66,6 @@ def update_uid_references(data, old_uid, new_uid, target_network_id):
|
||||||
if isinstance(pin_info, dict):
|
if isinstance(pin_info, dict):
|
||||||
if pin_info.get("source_instruction_uid") == old_uid:
|
if pin_info.get("source_instruction_uid") == old_uid:
|
||||||
pin_info["source_instruction_uid"] = new_uid
|
pin_info["source_instruction_uid"] = new_uid
|
||||||
print(f" - Actualizada referencia en instrucción {instruction.get('instruction_uid')} pin {pin_name}")
|
print(
|
||||||
|
f" - Actualizada referencia en instrucción {instruction.get('instruction_uid')} pin {pin_name}"
|
||||||
|
)
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
# processors/process_coil.py
|
# processors/process_coil.py
|
||||||
import sympy
|
import sympy
|
||||||
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, get_target_scl_name, format_variable_name
|
from .processor_utils import (
|
||||||
|
get_sympy_representation,
|
||||||
|
sympy_expr_to_scl,
|
||||||
|
get_target_scl_name,
|
||||||
|
format_variable_name,
|
||||||
|
)
|
||||||
from .symbol_manager import SymbolManager, extract_plc_variable_name
|
from .symbol_manager import SymbolManager, extract_plc_variable_name
|
||||||
|
|
||||||
SCL_SUFFIX = "_sympy_processed"
|
SCL_SUFFIX = "_sympy_processed"
|
||||||
|
|
||||||
|
|
||||||
def process_coil(instruction, network_id, sympy_map, symbol_manager, data):
|
def process_coil(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
"""Genera la asignación SCL para Coil, simplificando la entrada SymPy."""
|
"""Genera la asignación SCL para Coil, simplificando la entrada SymPy."""
|
||||||
instr_uid = instruction["instruction_uid"]
|
instr_uid = instruction["instruction_uid"]
|
||||||
|
@ -15,10 +21,14 @@ def process_coil(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
|
|
||||||
# Get input expression from SymPy map
|
# Get input expression from SymPy map
|
||||||
coil_input_info = instruction["inputs"].get("in")
|
coil_input_info = instruction["inputs"].get("in")
|
||||||
sympy_expr_in = get_sympy_representation(coil_input_info, network_id, sympy_map, symbol_manager)
|
sympy_expr_in = get_sympy_representation(
|
||||||
|
coil_input_info, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
|
|
||||||
# Get target variable SCL name
|
# Get target variable SCL name
|
||||||
target_scl_name = get_target_scl_name(instruction, "operand", network_id, default_to_temp=False) # Coil must have explicit target
|
target_scl_name = get_target_scl_name(
|
||||||
|
instruction, "operand", network_id, default_to_temp=False
|
||||||
|
) # Coil must have explicit target
|
||||||
|
|
||||||
# Check dependencies
|
# Check dependencies
|
||||||
if sympy_expr_in is None:
|
if sympy_expr_in is None:
|
||||||
|
@ -32,8 +42,8 @@ def process_coil(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
|
|
||||||
# *** Perform Simplification ***
|
# *** Perform Simplification ***
|
||||||
try:
|
try:
|
||||||
#simplified_expr = sympy.simplify_logic(sympy_expr_in, force=False)
|
# simplified_expr = sympy.simplify_logic(sympy_expr_in, force=False)
|
||||||
#simplified_expr = sympy_expr_in
|
# simplified_expr = sympy_expr_in
|
||||||
simplified_expr = sympy.logic.boolalg.to_dnf(sympy_expr_in, simplify=True)
|
simplified_expr = sympy.logic.boolalg.to_dnf(sympy_expr_in, simplify=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error during SymPy simplification for Coil {instr_uid}: {e}")
|
print(f"Error during SymPy simplification for Coil {instr_uid}: {e}")
|
||||||
|
@ -46,28 +56,52 @@ def process_coil(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
scl_assignment = f"{target_scl_name} := {condition_scl};"
|
scl_assignment = f"{target_scl_name} := {condition_scl};"
|
||||||
scl_final = scl_assignment
|
scl_final = scl_assignment
|
||||||
|
|
||||||
# --- Handle Edge Detector Memory Update (Logic similar to before) ---
|
# --- Handle Edge Detector Memory Update (FIXED: Avoid Duplication) ---
|
||||||
# Check if input comes from PBox/NBox and append memory update
|
# Check if input comes from PBox/NBox and incorporate memory update logic
|
||||||
mem_update_scl_combined = None
|
mem_update_scl_combined = None
|
||||||
if isinstance(coil_input_info, dict) and coil_input_info.get("type") == "connection":
|
if (
|
||||||
|
isinstance(coil_input_info, dict)
|
||||||
|
and coil_input_info.get("type") == "connection"
|
||||||
|
):
|
||||||
source_uid = coil_input_info.get("source_instruction_uid")
|
source_uid = coil_input_info.get("source_instruction_uid")
|
||||||
source_pin = coil_input_info.get("source_pin")
|
source_pin = coil_input_info.get("source_pin")
|
||||||
source_instruction = None
|
source_instruction = None
|
||||||
network_logic = next((net["logic"] for net in data["networks"] if net["id"] == network_id), [])
|
network_logic = next(
|
||||||
|
(net["logic"] for net in data["networks"] if net["id"] == network_id), []
|
||||||
|
)
|
||||||
for instr in network_logic:
|
for instr in network_logic:
|
||||||
if instr.get("instruction_uid") == source_uid:
|
if instr.get("instruction_uid") == source_uid:
|
||||||
source_instruction = instr
|
source_instruction = instr
|
||||||
break
|
break
|
||||||
if source_instruction:
|
if source_instruction:
|
||||||
# Check for the original type before suffix was added
|
# Check for the original type before suffix was added
|
||||||
orig_source_type = source_instruction.get("type", "").replace(SCL_SUFFIX, '').replace('_error', '')
|
orig_source_type = (
|
||||||
if orig_source_type in ["PBox", "NBox"] and '_edge_mem_update_scl' in source_instruction:
|
source_instruction.get("type", "")
|
||||||
mem_update_scl_combined = source_instruction.get('_edge_mem_update_scl')
|
.replace(SCL_SUFFIX, "")
|
||||||
|
.replace("_error", "")
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
orig_source_type in ["PBox", "NBox"]
|
||||||
|
and "_edge_mem_update_scl" in source_instruction
|
||||||
|
):
|
||||||
|
mem_update_scl_combined = source_instruction.get("_edge_mem_update_scl")
|
||||||
if mem_update_scl_combined:
|
if mem_update_scl_combined:
|
||||||
scl_final = f"{scl_assignment}\n{mem_update_scl_combined}"
|
# FIXED: Extract just the memory assignment part (before comment)
|
||||||
# Clear the source SCL?
|
mem_assignment_part = mem_update_scl_combined.split(" //")[
|
||||||
source_instruction['scl'] = f"// Edge Logic handled by Coil {instr_uid}"
|
0
|
||||||
|
].strip()
|
||||||
|
comment_part = (
|
||||||
|
" //" + mem_update_scl_combined.split(" //", 1)[1]
|
||||||
|
if " //" in mem_update_scl_combined
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add memory update BEFORE the coil assignment (correct P_TRIG order)
|
||||||
|
scl_final = f"{mem_assignment_part}{comment_part}\n{scl_assignment}"
|
||||||
|
# Mark the source as handled
|
||||||
|
source_instruction["scl"] = (
|
||||||
|
f"// Edge Logic handled by Coil {instr_uid}"
|
||||||
|
)
|
||||||
|
|
||||||
# Update instruction
|
# Update instruction
|
||||||
instruction["scl"] = scl_final
|
instruction["scl"] = scl_final
|
||||||
|
@ -80,7 +114,8 @@ def process_coil(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# --- Processor Information Function ---
|
# --- Processor Information Function ---
|
||||||
def get_processor_info():
|
def get_processor_info():
|
||||||
"""Devuelve la información para el procesador Coil."""
|
"""Devuelve la información para el procesador Coil."""
|
||||||
return {'type_name': 'coil', 'processor_func': process_coil, 'priority': 3}
|
return {"type_name": "coil", "processor_func": process_coil, "priority": 3}
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
# processors/process_contact.py
|
# processors/process_contact.py
|
||||||
import sympy
|
import sympy
|
||||||
from .processor_utils import get_sympy_representation, format_variable_name # Use new util
|
from .processor_utils import (
|
||||||
from .symbol_manager import SymbolManager, extract_plc_variable_name # Need symbol manager access
|
get_sympy_representation,
|
||||||
|
format_variable_name,
|
||||||
|
) # Use new util
|
||||||
|
from .symbol_manager import (
|
||||||
|
SymbolManager,
|
||||||
|
extract_plc_variable_name,
|
||||||
|
) # Need symbol manager access
|
||||||
|
|
||||||
# Define SCL_SUFFIX or import if needed globally
|
# Define SCL_SUFFIX or import if needed globally
|
||||||
SCL_SUFFIX = "_sympy_processed" # Indicate processing type
|
SCL_SUFFIX = "_sympy_processed" # Indicate processing type
|
||||||
|
|
||||||
def process_contact(instruction, network_id, sympy_map, symbol_manager, data): # Pass symbol_manager
|
|
||||||
|
def process_contact(
|
||||||
|
instruction, network_id, sympy_map, symbol_manager, data
|
||||||
|
): # Pass symbol_manager
|
||||||
"""Genera la expresión SymPy para Contact (normal o negado)."""
|
"""Genera la expresión SymPy para Contact (normal o negado)."""
|
||||||
instr_uid = instruction["instruction_uid"]
|
instr_uid = instruction["instruction_uid"]
|
||||||
instr_type_original = instruction.get("type", "Contact")
|
instr_type_original = instruction.get("type", "Contact")
|
||||||
|
@ -19,12 +28,16 @@ def process_contact(instruction, network_id, sympy_map, symbol_manager, data): #
|
||||||
|
|
||||||
# Get incoming SymPy expression (RLO)
|
# Get incoming SymPy expression (RLO)
|
||||||
in_input = instruction["inputs"].get("in")
|
in_input = instruction["inputs"].get("in")
|
||||||
sympy_expr_in = get_sympy_representation(in_input, network_id, sympy_map, symbol_manager)
|
sympy_expr_in = get_sympy_representation(
|
||||||
|
in_input, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
|
|
||||||
# Get operand SymPy Symbol
|
# Get operand SymPy Symbol
|
||||||
operand_info = instruction["inputs"].get("operand")
|
operand_info = instruction["inputs"].get("operand")
|
||||||
operand_plc_name = extract_plc_variable_name(operand_info)
|
operand_plc_name = extract_plc_variable_name(operand_info)
|
||||||
sympy_symbol_operand = symbol_manager.get_symbol(operand_plc_name) if operand_plc_name else None
|
sympy_symbol_operand = (
|
||||||
|
symbol_manager.get_symbol(operand_plc_name) if operand_plc_name else None
|
||||||
|
)
|
||||||
|
|
||||||
# Enhanced robustness: Handle cases where operand parsing fails
|
# Enhanced robustness: Handle cases where operand parsing fails
|
||||||
if operand_plc_name is None and operand_info:
|
if operand_plc_name is None and operand_info:
|
||||||
|
@ -36,7 +49,9 @@ def process_contact(instruction, network_id, sympy_map, symbol_manager, data): #
|
||||||
|
|
||||||
# If still no success, mark as error instead of hanging
|
# If still no success, mark as error instead of hanging
|
||||||
if sympy_symbol_operand is None:
|
if sympy_symbol_operand is None:
|
||||||
print(f"Error: Contact {instr_uid} - no se pudo extraer operando de {operand_info}")
|
print(
|
||||||
|
f"Error: Contact {instr_uid} - no se pudo extraer operando de {operand_info}"
|
||||||
|
)
|
||||||
instruction["scl"] = f"// ERROR: Contact {instr_uid} operando inválido"
|
instruction["scl"] = f"// ERROR: Contact {instr_uid} operando inválido"
|
||||||
instruction["type"] = instr_type_original + "_error"
|
instruction["type"] = instr_type_original + "_error"
|
||||||
return True
|
return True
|
||||||
|
@ -55,7 +70,9 @@ def process_contact(instruction, network_id, sympy_map, symbol_manager, data): #
|
||||||
return False # Dependencies not ready
|
return False # Dependencies not ready
|
||||||
|
|
||||||
# Apply negation using SymPy
|
# Apply negation using SymPy
|
||||||
current_term = sympy.Not(sympy_symbol_operand) if is_negated else sympy_symbol_operand
|
current_term = (
|
||||||
|
sympy.Not(sympy_symbol_operand) if is_negated else sympy_symbol_operand
|
||||||
|
)
|
||||||
|
|
||||||
# Combine with previous RLO using SymPy
|
# Combine with previous RLO using SymPy
|
||||||
# Simplify common cases: TRUE AND X -> X, FALSE AND X -> FALSE
|
# Simplify common cases: TRUE AND X -> X, FALSE AND X -> FALSE
|
||||||
|
@ -77,8 +94,9 @@ def process_contact(instruction, network_id, sympy_map, symbol_manager, data): #
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# --- Processor Information Function ---
|
# --- Processor Information Function ---
|
||||||
def get_processor_info():
|
def get_processor_info():
|
||||||
"""Devuelve la información para el procesador Contact."""
|
"""Devuelve la información para el procesador Contact."""
|
||||||
# Ensure 'data' argument is added if needed by the processor function signature change
|
# Ensure 'data' argument is added if needed by the processor function signature change
|
||||||
return {'type_name': 'contact', 'processor_func': process_contact, 'priority': 1}
|
return {"type_name": "contact", "processor_func": process_contact, "priority": 1}
|
||||||
|
|
|
@ -3,13 +3,22 @@
|
||||||
import sympy
|
import sympy
|
||||||
import traceback
|
import traceback
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# Usar las nuevas utilidades
|
# Usar las nuevas utilidades
|
||||||
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, get_target_scl_name, format_variable_name
|
from .processor_utils import (
|
||||||
|
get_sympy_representation,
|
||||||
|
sympy_expr_to_scl,
|
||||||
|
get_target_scl_name,
|
||||||
|
format_variable_name,
|
||||||
|
)
|
||||||
from .symbol_manager import SymbolManager
|
from .symbol_manager import SymbolManager
|
||||||
|
|
||||||
SCL_SUFFIX = "_sympy_processed"
|
SCL_SUFFIX = "_sympy_processed"
|
||||||
|
|
||||||
def process_math(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
|
|
||||||
|
def process_math(
|
||||||
|
instruction, network_id, sympy_map, symbol_manager: SymbolManager, data
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Genera SCL para operaciones matemáticas (SUB, MUL, DIV, CEIL), simplificando EN.
|
Genera SCL para operaciones matemáticas (SUB, MUL, DIV, CEIL), simplificando EN.
|
||||||
"""
|
"""
|
||||||
|
@ -22,7 +31,9 @@ def process_math(instruction, network_id, sympy_map, symbol_manager: SymbolManag
|
||||||
op_map = {"SUB": "-", "MUL": "*", "DIV": "/", "CEIL": "CEIL"}
|
op_map = {"SUB": "-", "MUL": "*", "DIV": "/", "CEIL": "CEIL"}
|
||||||
scl_operator = op_map.get(instr_type_original.upper())
|
scl_operator = op_map.get(instr_type_original.upper())
|
||||||
if not scl_operator:
|
if not scl_operator:
|
||||||
instruction["scl"] = f"// ERROR: Operación matemática no soportada: {instr_type_original}"
|
instruction["scl"] = (
|
||||||
|
f"// ERROR: Operación matemática no soportada: {instr_type_original}"
|
||||||
|
)
|
||||||
instruction["type"] = instr_type_original + "_error"
|
instruction["type"] = instr_type_original + "_error"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -30,20 +41,34 @@ def process_math(instruction, network_id, sympy_map, symbol_manager: SymbolManag
|
||||||
en_input = instruction["inputs"].get("en")
|
en_input = instruction["inputs"].get("en")
|
||||||
in1_info = instruction["inputs"].get("in1")
|
in1_info = instruction["inputs"].get("in1")
|
||||||
in2_info = instruction["inputs"].get("in2")
|
in2_info = instruction["inputs"].get("in2")
|
||||||
in_info = instruction["inputs"].get("in") # Para funciones de un solo operando como CEIL
|
in_info = instruction["inputs"].get(
|
||||||
|
"in"
|
||||||
|
) # Para funciones de un solo operando como CEIL
|
||||||
|
|
||||||
sympy_en_expr = get_sympy_representation(en_input, network_id, sympy_map, symbol_manager) if en_input else sympy.true
|
sympy_en_expr = (
|
||||||
|
get_sympy_representation(en_input, network_id, sympy_map, symbol_manager)
|
||||||
|
if en_input
|
||||||
|
else sympy.true
|
||||||
|
)
|
||||||
|
|
||||||
# Para CEIL solo necesitamos un operando
|
# Para CEIL solo necesitamos un operando
|
||||||
if instr_type_original.upper() == "CEIL":
|
if instr_type_original.upper() == "CEIL":
|
||||||
op1_sympy_or_const = get_sympy_representation(in_info, network_id, sympy_map, symbol_manager)
|
op1_sympy_or_const = get_sympy_representation(
|
||||||
|
in_info, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
op2_sympy_or_const = None
|
op2_sympy_or_const = None
|
||||||
else:
|
else:
|
||||||
op1_sympy_or_const = get_sympy_representation(in1_info, network_id, sympy_map, symbol_manager)
|
op1_sympy_or_const = get_sympy_representation(
|
||||||
op2_sympy_or_const = get_sympy_representation(in2_info, network_id, sympy_map, symbol_manager)
|
in1_info, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
|
op2_sympy_or_const = get_sympy_representation(
|
||||||
|
in2_info, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
|
|
||||||
# Obtener destino SCL
|
# Obtener destino SCL
|
||||||
target_scl_name = get_target_scl_name(instruction, "out", network_id, default_to_temp=True)
|
target_scl_name = get_target_scl_name(
|
||||||
|
instruction, "out", network_id, default_to_temp=True
|
||||||
|
)
|
||||||
|
|
||||||
# Verificar dependencias
|
# Verificar dependencias
|
||||||
if sympy_en_expr is None or op1_sympy_or_const is None or target_scl_name is None:
|
if sympy_en_expr is None or op1_sympy_or_const is None or target_scl_name is None:
|
||||||
|
@ -62,8 +87,12 @@ def process_math(instruction, network_id, sympy_map, symbol_manager: SymbolManag
|
||||||
|
|
||||||
# Añadir paréntesis si contienen operadores (más seguro)
|
# Añadir paréntesis si contienen operadores (más seguro)
|
||||||
# La función sympy_expr_to_scl debería idealmente manejar esto, pero doble chequeo simple:
|
# La función sympy_expr_to_scl debería idealmente manejar esto, pero doble chequeo simple:
|
||||||
op1_scl_formatted = f"({op1_scl})" if re.search(r'[+\-*/ ]', op1_scl) else op1_scl
|
op1_scl_formatted = (
|
||||||
op2_scl_formatted = f"({op2_scl})" if re.search(r'[+\-*/ ]', op2_scl) else op2_scl
|
f"({op1_scl})" if re.search(r"[+\-*/ ]", op1_scl) else op1_scl
|
||||||
|
)
|
||||||
|
op2_scl_formatted = (
|
||||||
|
f"({op2_scl})" if re.search(r"[+\-*/ ]", op2_scl) else op2_scl
|
||||||
|
)
|
||||||
|
|
||||||
scl_core = f"{target_scl_name} := {op1_scl_formatted} {scl_operator} {op2_scl_formatted};"
|
scl_core = f"{target_scl_name} := {op1_scl_formatted} {scl_operator} {op2_scl_formatted};"
|
||||||
|
|
||||||
|
@ -71,8 +100,10 @@ def process_math(instruction, network_id, sympy_map, symbol_manager: SymbolManag
|
||||||
scl_final = ""
|
scl_final = ""
|
||||||
if sympy_en_expr != sympy.true:
|
if sympy_en_expr != sympy.true:
|
||||||
try:
|
try:
|
||||||
#simplified_en_expr = sympy.simplify_logic(sympy_en_expr, force=True)
|
# simplified_en_expr = sympy.simplify_logic(sympy_en_expr, force=True)
|
||||||
simplified_en_expr = sympy.logic.boolalg.to_dnf(sympy_en_expr, simplify=True)
|
simplified_en_expr = sympy.logic.boolalg.to_dnf(
|
||||||
|
sympy_en_expr, simplify=True
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error simplifying EN for {instr_type_original} {instr_uid}: {e}")
|
print(f"Error simplifying EN for {instr_type_original} {instr_uid}: {e}")
|
||||||
simplified_en_expr = sympy_en_expr # Fallback
|
simplified_en_expr = sympy_en_expr # Fallback
|
||||||
|
@ -95,12 +126,13 @@ def process_math(instruction, network_id, sympy_map, symbol_manager: SymbolManag
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# --- Processor Information Function ---
|
# --- Processor Information Function ---
|
||||||
def get_processor_info():
|
def get_processor_info():
|
||||||
"""Devuelve info para SUB, MUL, DIV, CEIL."""
|
"""Devuelve info para SUB, MUL, DIV, CEIL."""
|
||||||
return [
|
return [
|
||||||
{'type_name': 'sub', 'processor_func': process_math, 'priority': 4},
|
{"type_name": "sub", "processor_func": process_math, "priority": 4},
|
||||||
{'type_name': 'mul', 'processor_func': process_math, 'priority': 4},
|
{"type_name": "mul", "processor_func": process_math, "priority": 4},
|
||||||
{'type_name': 'div', 'processor_func': process_math, 'priority': 4},
|
{"type_name": "div", "processor_func": process_math, "priority": 4},
|
||||||
{'type_name': 'ceil', 'processor_func': process_math, 'priority': 4}
|
{"type_name": "ceil", "processor_func": process_math, "priority": 4},
|
||||||
]
|
]
|
|
@ -2,12 +2,14 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sympy
|
import sympy
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
# Usar las nuevas utilidades
|
# Usar las nuevas utilidades
|
||||||
from .processor_utils import get_sympy_representation
|
from .processor_utils import get_sympy_representation
|
||||||
from .symbol_manager import SymbolManager
|
from .symbol_manager import SymbolManager
|
||||||
|
|
||||||
SCL_SUFFIX = "_sympy_processed" # Nuevo sufijo
|
SCL_SUFFIX = "_sympy_processed" # Nuevo sufijo
|
||||||
|
|
||||||
|
|
||||||
def process_o(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
|
def process_o(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
|
||||||
"""Genera la expresión SymPy para la operación lógica O (OR)."""
|
"""Genera la expresión SymPy para la operación lógica O (OR)."""
|
||||||
instr_uid = instruction["instruction_uid"]
|
instr_uid = instruction["instruction_uid"]
|
||||||
|
@ -16,7 +18,9 @@ def process_o(instruction, network_id, sympy_map, symbol_manager: SymbolManager,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Buscar todas las entradas 'in', 'in1', 'in2', ...
|
# Buscar todas las entradas 'in', 'in1', 'in2', ...
|
||||||
input_pins = sorted([pin for pin in instruction.get("inputs", {}) if pin.startswith("in")])
|
input_pins = sorted(
|
||||||
|
[pin for pin in instruction.get("inputs", {}) if pin.startswith("in")]
|
||||||
|
)
|
||||||
|
|
||||||
if not input_pins:
|
if not input_pins:
|
||||||
print(f"Error: O {instr_uid} sin pines de entrada (inX).")
|
print(f"Error: O {instr_uid} sin pines de entrada (inX).")
|
||||||
|
@ -30,7 +34,9 @@ def process_o(instruction, network_id, sympy_map, symbol_manager: SymbolManager,
|
||||||
|
|
||||||
for pin in input_pins:
|
for pin in input_pins:
|
||||||
input_info = instruction["inputs"][pin]
|
input_info = instruction["inputs"][pin]
|
||||||
sympy_expr = get_sympy_representation(input_info, network_id, sympy_map, symbol_manager)
|
sympy_expr = get_sympy_representation(
|
||||||
|
input_info, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
|
|
||||||
if sympy_expr is None:
|
if sympy_expr is None:
|
||||||
all_resolved = False
|
all_resolved = False
|
||||||
|
@ -65,7 +71,6 @@ def process_o(instruction, network_id, sympy_map, symbol_manager: SymbolManager,
|
||||||
# print(f"DEBUG: O {instr_uid} simplification failed: {e}")
|
# print(f"DEBUG: O {instr_uid} simplification failed: {e}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Guardar la expresión SymPy resultante en el mapa para 'out'
|
# Guardar la expresión SymPy resultante en el mapa para 'out'
|
||||||
map_key_out = (network_id, instr_uid, "out")
|
map_key_out = (network_id, instr_uid, "out")
|
||||||
sympy_map[map_key_out] = result_sympy_expr
|
sympy_map[map_key_out] = result_sympy_expr
|
||||||
|
@ -76,7 +81,8 @@ def process_o(instruction, network_id, sympy_map, symbol_manager: SymbolManager,
|
||||||
# La instrucción 'O' no tiene ENO propio, propaga el resultado por 'out'
|
# La instrucción 'O' no tiene ENO propio, propaga el resultado por 'out'
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# --- Processor Information Function ---
|
# --- Processor Information Function ---
|
||||||
def get_processor_info():
|
def get_processor_info():
|
||||||
"""Devuelve la información para la operación lógica O (OR)."""
|
"""Devuelve la información para la operación lógica O (OR)."""
|
||||||
return {'type_name': 'o', 'processor_func': process_o, 'priority': 1}
|
return {"type_name": "o", "processor_func": process_o, "priority": 1}
|
||||||
|
|
|
@ -2,11 +2,17 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sympy
|
import sympy
|
||||||
import traceback
|
import traceback
|
||||||
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, get_target_scl_name, format_variable_name
|
from .processor_utils import (
|
||||||
|
get_sympy_representation,
|
||||||
|
sympy_expr_to_scl,
|
||||||
|
get_target_scl_name,
|
||||||
|
format_variable_name,
|
||||||
|
)
|
||||||
from .symbol_manager import SymbolManager
|
from .symbol_manager import SymbolManager
|
||||||
|
|
||||||
SCL_SUFFIX = "_sympy_processed"
|
SCL_SUFFIX = "_sympy_processed"
|
||||||
|
|
||||||
|
|
||||||
def process_sr(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
|
def process_sr(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
|
||||||
"""
|
"""
|
||||||
Genera SCL para Set/Reset flip-flop (Sr).
|
Genera SCL para Set/Reset flip-flop (Sr).
|
||||||
|
@ -23,7 +29,9 @@ def process_sr(instruction, network_id, sympy_map, symbol_manager: SymbolManager
|
||||||
|
|
||||||
# Si no tiene conexiones, marcar como procesado sin generar código
|
# Si no tiene conexiones, marcar como procesado sin generar código
|
||||||
if not inputs and not outputs:
|
if not inputs and not outputs:
|
||||||
instruction["scl"] = "// Sr flip-flop sin conexiones - procesado como placeholder"
|
instruction["scl"] = (
|
||||||
|
"// Sr flip-flop sin conexiones - procesado como placeholder"
|
||||||
|
)
|
||||||
instruction["type"] = instr_type_original + SCL_SUFFIX
|
instruction["type"] = instr_type_original + SCL_SUFFIX
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -33,7 +41,8 @@ def process_sr(instruction, network_id, sympy_map, symbol_manager: SymbolManager
|
||||||
instruction["type"] = instr_type_original + "_error"
|
instruction["type"] = instr_type_original + "_error"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# --- Processor Information Function ---
|
# --- Processor Information Function ---
|
||||||
def get_processor_info():
|
def get_processor_info():
|
||||||
"""Devuelve la información para el procesador Sr."""
|
"""Devuelve la información para el procesador Sr."""
|
||||||
return {'type_name': 'sr', 'processor_func': process_sr, 'priority': 4}
|
return {"type_name": "sr", "processor_func": process_sr, "priority": 4}
|
||||||
|
|
|
@ -2,25 +2,40 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sympy
|
import sympy
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
# Usar las nuevas utilidades
|
# Usar las nuevas utilidades
|
||||||
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, format_variable_name, get_target_scl_name
|
from .processor_utils import (
|
||||||
|
get_sympy_representation,
|
||||||
|
sympy_expr_to_scl,
|
||||||
|
format_variable_name,
|
||||||
|
get_target_scl_name,
|
||||||
|
)
|
||||||
from .symbol_manager import SymbolManager, extract_plc_variable_name
|
from .symbol_manager import SymbolManager, extract_plc_variable_name
|
||||||
|
|
||||||
SCL_SUFFIX = "_sympy_processed"
|
SCL_SUFFIX = "_sympy_processed"
|
||||||
|
|
||||||
def process_timer(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
|
|
||||||
|
def process_timer(
|
||||||
|
instruction, network_id, sympy_map, symbol_manager: SymbolManager, data
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Genera SCL para Temporizadores (TON, TOF) directamente.
|
Genera SCL para Temporizadores (TON, TOF) directamente.
|
||||||
Requiere datos de instancia.
|
Requiere datos de instancia.
|
||||||
"""
|
"""
|
||||||
instr_uid = instruction["instruction_uid"]
|
instr_uid = instruction["instruction_uid"]
|
||||||
instr_type_original = instruction.get("type", "").replace(SCL_SUFFIX,"").replace("_error","") # TON o TOF
|
instr_type_original = (
|
||||||
if instruction.get("type","").endswith(SCL_SUFFIX) or "_error" in instruction.get("type",""):
|
instruction.get("type", "").replace(SCL_SUFFIX, "").replace("_error", "")
|
||||||
|
) # TON o TOF
|
||||||
|
if instruction.get("type", "").endswith(SCL_SUFFIX) or "_error" in instruction.get(
|
||||||
|
"type", ""
|
||||||
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
scl_timer_type = instr_type_original.upper()
|
scl_timer_type = instr_type_original.upper()
|
||||||
if scl_timer_type not in ["TON", "TOF", "TP"]:
|
if scl_timer_type not in ["TON", "TOF", "TP"]:
|
||||||
instruction["scl"] = f"// ERROR: Tipo de temporizador directo no soportado: {instr_type_original}"
|
instruction["scl"] = (
|
||||||
|
f"// ERROR: Tipo de temporizador directo no soportado: {instr_type_original}"
|
||||||
|
)
|
||||||
instruction["type"] = instr_type_original + "_error"
|
instruction["type"] = instr_type_original + "_error"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -34,12 +49,19 @@ def process_timer(instruction, network_id, sympy_map, symbol_manager: SymbolMana
|
||||||
# Asumir que debe estar declarado como STAT si no hay instance_db
|
# Asumir que debe estar declarado como STAT si no hay instance_db
|
||||||
instance_plc_name = instruction.get("instance_name") # Nombre directo?
|
instance_plc_name = instruction.get("instance_name") # Nombre directo?
|
||||||
if not instance_plc_name:
|
if not instance_plc_name:
|
||||||
instance_plc_name = f"#{scl_timer_type}_INSTANCE_{instr_uid}" # Placeholder final
|
instance_plc_name = (
|
||||||
print(f"Advertencia: No se encontró nombre/instancia para {instr_type_original} UID {instr_uid}. Usando placeholder '{instance_plc_name}'.")
|
f"#{scl_timer_type}_INSTANCE_{instr_uid}" # Placeholder final
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"Advertencia: No se encontró nombre/instancia para {instr_type_original} UID {instr_uid}. Usando placeholder '{instance_plc_name}'."
|
||||||
|
)
|
||||||
|
|
||||||
|
sympy_in_expr = get_sympy_representation(
|
||||||
sympy_in_expr = get_sympy_representation(in_info, network_id, sympy_map, symbol_manager)
|
in_info, network_id, sympy_map, symbol_manager
|
||||||
sympy_or_const_pt = get_sympy_representation(pt_info, network_id, sympy_map, symbol_manager)
|
)
|
||||||
|
sympy_or_const_pt = get_sympy_representation(
|
||||||
|
pt_info, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
|
|
||||||
# Verificar dependencias
|
# Verificar dependencias
|
||||||
if sympy_in_expr is None or sympy_or_const_pt is None or instance_plc_name is None:
|
if sympy_in_expr is None or sympy_or_const_pt is None or instance_plc_name is None:
|
||||||
|
@ -53,6 +75,12 @@ def process_timer(instruction, network_id, sympy_map, symbol_manager: SymbolMana
|
||||||
pt_scl = sympy_expr_to_scl(sympy_or_const_pt, symbol_manager)
|
pt_scl = sympy_expr_to_scl(sympy_or_const_pt, symbol_manager)
|
||||||
|
|
||||||
# Generar la llamada SCL
|
# Generar la llamada SCL
|
||||||
|
# ENHANCED: Only add TODO comment if it's not an auto-generated placeholder
|
||||||
|
if instance_plc_name.startswith("#") and "_INSTANCE_" in instance_plc_name:
|
||||||
|
# It's an auto-generated placeholder, will be declared automatically in VAR_TEMP
|
||||||
|
scl_call = f"{instance_name_scl}(IN := {in_scl}, PT := {pt_scl});"
|
||||||
|
else:
|
||||||
|
# It's a named instance that might need manual declaration
|
||||||
scl_call = f"{instance_name_scl}(IN := {in_scl}, PT := {pt_scl}); // TODO: Declarar {instance_name_scl} : {scl_timer_type};"
|
scl_call = f"{instance_name_scl}(IN := {in_scl}, PT := {pt_scl}); // TODO: Declarar {instance_name_scl} : {scl_timer_type};"
|
||||||
|
|
||||||
# Actualizar instrucción
|
# Actualizar instrucción
|
||||||
|
@ -67,7 +95,9 @@ def process_timer(instruction, network_id, sympy_map, symbol_manager: SymbolMana
|
||||||
if sympy_q_symbol:
|
if sympy_q_symbol:
|
||||||
sympy_map[map_key_q] = sympy_q_symbol # Store the SYMBOL
|
sympy_map[map_key_q] = sympy_q_symbol # Store the SYMBOL
|
||||||
else:
|
else:
|
||||||
print(f"Error: Could not create symbol for {q_output_scl_access} in {instr_type_original} {instr_uid}")
|
print(
|
||||||
|
f"Error: Could not create symbol for {q_output_scl_access} in {instr_type_original} {instr_uid}"
|
||||||
|
)
|
||||||
sympy_map[map_key_q] = None
|
sympy_map[map_key_q] = None
|
||||||
|
|
||||||
map_key_et = (network_id, instr_uid, "ET") # Pin estándar SCL
|
map_key_et = (network_id, instr_uid, "ET") # Pin estándar SCL
|
||||||
|
@ -83,16 +113,21 @@ def process_timer(instruction, network_id, sympy_map, symbol_manager: SymbolMana
|
||||||
sympy_map[map_key_eno] = sympy.true
|
sympy_map[map_key_eno] = sympy.true
|
||||||
|
|
||||||
# *** Also handle common aliases ***
|
# *** Also handle common aliases ***
|
||||||
map_key_out = (network_id, instr_uid, "out") # Some connections might look for "out"
|
map_key_out = (
|
||||||
|
network_id,
|
||||||
|
instr_uid,
|
||||||
|
"out",
|
||||||
|
) # Some connections might look for "out"
|
||||||
sympy_map[map_key_out] = sympy_q_symbol # Map "out" to Q output
|
sympy_map[map_key_out] = sympy_q_symbol # Map "out" to Q output
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# --- Processor Information Function ---
|
# --- Processor Information Function ---
|
||||||
def get_processor_info():
|
def get_processor_info():
|
||||||
"""Devuelve info para TON, TOF y TP directos."""
|
"""Devuelve info para TON, TOF y TP directos."""
|
||||||
return [
|
return [
|
||||||
{'type_name': 'ton', 'processor_func': process_timer, 'priority': 5},
|
{"type_name": "ton", "processor_func": process_timer, "priority": 5},
|
||||||
{'type_name': 'tof', 'processor_func': process_timer, 'priority': 5},
|
{"type_name": "tof", "processor_func": process_timer, "priority": 5},
|
||||||
{'type_name': 'tp', 'processor_func': process_timer, 'priority': 5}
|
{"type_name": "tp", "processor_func": process_timer, "priority": 5},
|
||||||
]
|
]
|
|
@ -6,6 +6,7 @@ from .symbol_manager import SymbolManager, extract_plc_variable_name
|
||||||
|
|
||||||
SCL_SUFFIX = "_sympy_processed" # <<< AÑADE ESTA LÍNEA
|
SCL_SUFFIX = "_sympy_processed" # <<< AÑADE ESTA LÍNEA
|
||||||
|
|
||||||
|
|
||||||
def format_variable_name(name):
|
def format_variable_name(name):
|
||||||
"""Limpia el nombre de la variable para SCL."""
|
"""Limpia el nombre de la variable para SCL."""
|
||||||
if not name:
|
if not name:
|
||||||
|
@ -21,6 +22,7 @@ def format_variable_name(name):
|
||||||
name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
|
name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
|
||||||
return prefix + name
|
return prefix + name
|
||||||
|
|
||||||
|
|
||||||
def get_sympy_representation(source_info, network_id, sympy_map, symbol_manager):
|
def get_sympy_representation(source_info, network_id, sympy_map, symbol_manager):
|
||||||
"""Gets the SymPy expression object representing the source."""
|
"""Gets the SymPy expression object representing the source."""
|
||||||
if not source_info:
|
if not source_info:
|
||||||
|
@ -32,7 +34,9 @@ def get_sympy_representation(source_info, network_id, sympy_map, symbol_manager)
|
||||||
sympy_parts = []
|
sympy_parts = []
|
||||||
all_resolved = True
|
all_resolved = True
|
||||||
for sub_source in source_info:
|
for sub_source in source_info:
|
||||||
sub_sympy = get_sympy_representation(sub_source, network_id, sympy_map, symbol_manager)
|
sub_sympy = get_sympy_representation(
|
||||||
|
sub_source, network_id, sympy_map, symbol_manager
|
||||||
|
)
|
||||||
if sub_sympy is None:
|
if sub_sympy is None:
|
||||||
all_resolved = False
|
all_resolved = False
|
||||||
break
|
break
|
||||||
|
@ -78,7 +82,9 @@ def get_sympy_representation(source_info, network_id, sympy_map, symbol_manager)
|
||||||
source_info.get("source_pin"),
|
source_info.get("source_pin"),
|
||||||
)
|
)
|
||||||
# Return the SymPy object from the map
|
# Return the SymPy object from the map
|
||||||
return sympy_map.get(map_key) # Returns None if not found (dependency not ready)
|
return sympy_map.get(
|
||||||
|
map_key
|
||||||
|
) # Returns None if not found (dependency not ready)
|
||||||
# Nueva lógica para manejar parámetros de tipo Address
|
# Nueva lógica para manejar parámetros de tipo Address
|
||||||
elif source_type == "unknown_structure" and source_scope == "Address":
|
elif source_type == "unknown_structure" and source_scope == "Address":
|
||||||
# Crear una representación especial para direcciones indirectas
|
# Crear una representación especial para direcciones indirectas
|
||||||
|
@ -117,11 +123,15 @@ def get_sympy_representation(source_info, network_id, sympy_map, symbol_manager)
|
||||||
print(f"Warning: Unknown source type: {source_info}")
|
print(f"Warning: Unknown source type: {source_info}")
|
||||||
return None # Cannot resolve
|
return None # Cannot resolve
|
||||||
|
|
||||||
|
|
||||||
def sympy_expr_to_scl(expr, symbol_manager, format_prec=5):
|
def sympy_expr_to_scl(expr, symbol_manager, format_prec=5):
|
||||||
"""Converts a SymPy expression to an SCL string using the symbol map."""
|
"""Converts a SymPy expression to an SCL string using the symbol map."""
|
||||||
if expr is None: return "/* ERROR: None expression */"
|
if expr is None:
|
||||||
if expr == sympy.true: return "TRUE"
|
return "/* ERROR: None expression */"
|
||||||
if expr == sympy.false: return "FALSE"
|
if expr == sympy.true:
|
||||||
|
return "TRUE"
|
||||||
|
if expr == sympy.false:
|
||||||
|
return "FALSE"
|
||||||
|
|
||||||
# Use sympy's string printer with custom settings if needed
|
# Use sympy's string printer with custom settings if needed
|
||||||
# For boolean, standard printing might be okay, but need to substitute symbols
|
# For boolean, standard printing might be okay, but need to substitute symbols
|
||||||
|
@ -137,21 +147,23 @@ def sympy_expr_to_scl(expr, symbol_manager, format_prec=5):
|
||||||
# Sort keys by length descending to replace longer IDs first
|
# Sort keys by length descending to replace longer IDs first
|
||||||
for py_id in sorted(inverse_map.keys(), key=len, reverse=True):
|
for py_id in sorted(inverse_map.keys(), key=len, reverse=True):
|
||||||
# Use word boundaries to avoid replacing parts of other IDs
|
# Use word boundaries to avoid replacing parts of other IDs
|
||||||
scl_str = re.sub(r'\b' + re.escape(py_id) + r'\b', inverse_map[py_id], scl_str)
|
scl_str = re.sub(
|
||||||
|
r"\b" + re.escape(py_id) + r"\b", inverse_map[py_id], scl_str
|
||||||
|
)
|
||||||
|
|
||||||
# Replace SymPy operators/functions with SCL equivalents
|
# Replace SymPy operators/functions with SCL equivalents
|
||||||
scl_str = scl_str.replace('&', ' AND ')
|
scl_str = scl_str.replace("&", " AND ")
|
||||||
scl_str = scl_str.replace('|', ' OR ')
|
scl_str = scl_str.replace("|", " OR ")
|
||||||
scl_str = scl_str.replace('^', ' XOR ') # If XOR is used
|
scl_str = scl_str.replace("^", " XOR ") # If XOR is used
|
||||||
scl_str = scl_str.replace('~', 'NOT ')
|
scl_str = scl_str.replace("~", "NOT ")
|
||||||
# Add spaces around operators if needed after substitution
|
# Add spaces around operators if needed after substitution
|
||||||
scl_str = re.sub(r'AND', ' AND ', scl_str)
|
scl_str = re.sub(r"AND", " AND ", scl_str)
|
||||||
scl_str = re.sub(r'OR', ' OR ', scl_str)
|
scl_str = re.sub(r"OR", " OR ", scl_str)
|
||||||
scl_str = re.sub(r'XOR', ' XOR ', scl_str)
|
scl_str = re.sub(r"XOR", " XOR ", scl_str)
|
||||||
scl_str = re.sub(r'NOT', 'NOT ', scl_str) # Space after NOT
|
scl_str = re.sub(r"NOT", "NOT ", scl_str) # Space after NOT
|
||||||
|
|
||||||
# Clean up potential double spaces, etc.
|
# Clean up potential double spaces, etc.
|
||||||
scl_str = re.sub(r'\s+', ' ', scl_str).strip()
|
scl_str = re.sub(r"\s+", " ", scl_str).strip()
|
||||||
# Handle parentheses potentially added by sstr - maybe remove redundant ones?
|
# Handle parentheses potentially added by sstr - maybe remove redundant ones?
|
||||||
# Be careful not to break operator precedence.
|
# Be careful not to break operator precedence.
|
||||||
|
|
||||||
|
@ -162,6 +174,7 @@ def sympy_expr_to_scl(expr, symbol_manager, format_prec=5):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return f"/* ERROR converting SymPy: {expr} */"
|
return f"/* ERROR converting SymPy: {expr} */"
|
||||||
|
|
||||||
|
|
||||||
def get_scl_representation(source_info, network_id, scl_map, access_map):
|
def get_scl_representation(source_info, network_id, scl_map, access_map):
|
||||||
if not source_info:
|
if not source_info:
|
||||||
return None
|
return None
|
||||||
|
@ -254,6 +267,7 @@ def get_scl_representation(source_info, network_id, scl_map, access_map):
|
||||||
print(f"Advertencia: Tipo de fuente desconocido: {source_info}")
|
print(f"Advertencia: Tipo de fuente desconocido: {source_info}")
|
||||||
return f"_ERR_INVALID_SRC_TYPE_"
|
return f"_ERR_INVALID_SRC_TYPE_"
|
||||||
|
|
||||||
|
|
||||||
def format_variable_name(name):
|
def format_variable_name(name):
|
||||||
"""Limpia el nombre de la variable para SCL."""
|
"""Limpia el nombre de la variable para SCL."""
|
||||||
if not name:
|
if not name:
|
||||||
|
@ -282,6 +296,7 @@ def format_variable_name(name):
|
||||||
|
|
||||||
return prefix + name
|
return prefix + name
|
||||||
|
|
||||||
|
|
||||||
def generate_temp_var_name(network_id, instr_uid, pin_name):
|
def generate_temp_var_name(network_id, instr_uid, pin_name):
|
||||||
net_id_clean = str(network_id).replace("-", "_")
|
net_id_clean = str(network_id).replace("-", "_")
|
||||||
instr_uid_clean = str(instr_uid).replace("-", "_")
|
instr_uid_clean = str(instr_uid).replace("-", "_")
|
||||||
|
@ -289,13 +304,19 @@ def generate_temp_var_name(network_id, instr_uid, pin_name):
|
||||||
# Usar # para variables temporales SCL estándar
|
# Usar # para variables temporales SCL estándar
|
||||||
return f"#_temp_{net_id_clean}_{instr_uid_clean}_{pin_name_clean}"
|
return f"#_temp_{net_id_clean}_{instr_uid_clean}_{pin_name_clean}"
|
||||||
|
|
||||||
|
|
||||||
def get_target_scl_name(instruction, pin_name, network_id, default_to_temp=True):
|
def get_target_scl_name(instruction, pin_name, network_id, default_to_temp=True):
|
||||||
"""Gets the SCL formatted name for a target variable.
|
"""Gets the SCL formatted name for a target variable.
|
||||||
Handles instruction outputs AND specific inputs like Coil operand.
|
Handles instruction outputs AND specific inputs like Coil operand.
|
||||||
"""
|
"""
|
||||||
instr_uid = instruction["instruction_uid"]
|
instr_uid = instruction["instruction_uid"]
|
||||||
# Ahora SCL_SUFFIX está definido en este módulo
|
# Ahora SCL_SUFFIX está definido en este módulo
|
||||||
instr_type_upper = instruction.get("type", "").upper().replace(SCL_SUFFIX.upper(), "").replace("_ERROR", "") # Check original type
|
instr_type_upper = (
|
||||||
|
instruction.get("type", "")
|
||||||
|
.upper()
|
||||||
|
.replace(SCL_SUFFIX.upper(), "")
|
||||||
|
.replace("_ERROR", "")
|
||||||
|
) # Check original type
|
||||||
target_info = None
|
target_info = None
|
||||||
|
|
||||||
# Special handling for inputs that represent the target variable
|
# Special handling for inputs that represent the target variable
|
||||||
|
@ -308,7 +329,11 @@ def get_target_scl_name(instruction, pin_name, network_id, default_to_temp=True)
|
||||||
# Default: Assume pin_name refers to an output pin
|
# Default: Assume pin_name refers to an output pin
|
||||||
output_pin_data = instruction.get("outputs", {}).get(pin_name)
|
output_pin_data = instruction.get("outputs", {}).get(pin_name)
|
||||||
# Check if it's a list and has one connection (standard case)
|
# Check if it's a list and has one connection (standard case)
|
||||||
if (output_pin_data and isinstance(output_pin_data, list) and len(output_pin_data) == 1):
|
if (
|
||||||
|
output_pin_data
|
||||||
|
and isinstance(output_pin_data, list)
|
||||||
|
and len(output_pin_data) == 1
|
||||||
|
):
|
||||||
target_info = output_pin_data[0]
|
target_info = output_pin_data[0]
|
||||||
# Add handling for direct output assignment if your JSON structure supports it
|
# Add handling for direct output assignment if your JSON structure supports it
|
||||||
|
|
||||||
|
@ -319,7 +344,9 @@ def get_target_scl_name(instruction, pin_name, network_id, default_to_temp=True)
|
||||||
if plc_name:
|
if plc_name:
|
||||||
target_scl = format_variable_name(plc_name) # Use existing util
|
target_scl = format_variable_name(plc_name) # Use existing util
|
||||||
else:
|
else:
|
||||||
print(f"Error: Target variable for {instr_uid}.{pin_name} has no name (UID: {target_info.get('uid')}).")
|
print(
|
||||||
|
f"Error: Target variable for {instr_uid}.{pin_name} has no name (UID: {target_info.get('uid')})."
|
||||||
|
)
|
||||||
elif target_info.get("type") == "unknown_structure":
|
elif target_info.get("type") == "unknown_structure":
|
||||||
# Handle direct memory addresses like DB960.X448.0
|
# Handle direct memory addresses like DB960.X448.0
|
||||||
area = target_info.get("Area")
|
area = target_info.get("Area")
|
||||||
|
@ -353,18 +380,23 @@ def get_target_scl_name(instruction, pin_name, network_id, default_to_temp=True)
|
||||||
target_scl = f"%{area}D{byte_offset}"
|
target_scl = f"%{area}D{byte_offset}"
|
||||||
else:
|
else:
|
||||||
target_scl = f"%{area}{byte_offset}"
|
target_scl = f"%{area}{byte_offset}"
|
||||||
print(f"INFO: Converted direct address to SCL: {target_scl} for {instr_uid}.{pin_name}")
|
print(
|
||||||
|
f"INFO: Converted direct address to SCL: {target_scl} for {instr_uid}.{pin_name}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print(f"Error: Incomplete address info for {instr_uid}.{pin_name}: Area={area}, Block={block_number}, Offset={bit_offset}")
|
print(
|
||||||
|
f"Error: Incomplete address info for {instr_uid}.{pin_name}: Area={area}, Block={block_number}, Offset={bit_offset}"
|
||||||
|
)
|
||||||
elif target_info.get("type") == "constant":
|
elif target_info.get("type") == "constant":
|
||||||
print(f"Advertencia: Attempt to write to constant target {instr_uid}.{pin_name} (UID: {target_info.get('uid')}).")
|
print(
|
||||||
|
f"Advertencia: Attempt to write to constant target {instr_uid}.{pin_name} (UID: {target_info.get('uid')})."
|
||||||
|
)
|
||||||
# else: # Handle other target types if needed
|
# else: # Handle other target types if needed
|
||||||
# print(f"Advertencia: Target {instr_uid}.{pin_name} is not a variable: {target_info.get('type')}.")
|
# print(f"Advertencia: Target {instr_uid}.{pin_name} is not a variable: {target_info.get('type')}.")
|
||||||
# else: # No target info found for the specified pin
|
# else: # No target info found for the specified pin
|
||||||
# print(f"DEBUG: No target info found for {instr_uid}.{pin_name}")
|
# print(f"DEBUG: No target info found for {instr_uid}.{pin_name}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Handle default_to_temp logic
|
# Handle default_to_temp logic
|
||||||
if target_scl:
|
if target_scl:
|
||||||
return target_scl
|
return target_scl
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import sympy
|
import sympy
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
class SymbolManager:
|
class SymbolManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# plc_name -> py_id (e.g., '"DB".Var' -> 'v0_')
|
# plc_name -> py_id (e.g., '"DB".Var' -> 'v0_')
|
||||||
|
@ -29,7 +30,9 @@ class SymbolManager:
|
||||||
print("Warning: Attempted to get symbol for None PLC name.")
|
print("Warning: Attempted to get symbol for None PLC name.")
|
||||||
return None # Or handle error appropriately
|
return None # Or handle error appropriately
|
||||||
if plc_var_name.upper() in self.reserved_names:
|
if plc_var_name.upper() in self.reserved_names:
|
||||||
print(f"Warning: Attempted to create symbol for reserved name: {plc_var_name}")
|
print(
|
||||||
|
f"Warning: Attempted to create symbol for reserved name: {plc_var_name}"
|
||||||
|
)
|
||||||
return None # Or handle differently (e.g., return sympy.true/false?)
|
return None # Or handle differently (e.g., return sympy.true/false?)
|
||||||
|
|
||||||
if plc_var_name not in self.plc_to_py_id:
|
if plc_var_name not in self.plc_to_py_id:
|
||||||
|
@ -51,6 +54,7 @@ class SymbolManager:
|
||||||
"""Returns the map needed for postprocessing (py_id -> plc_name)."""
|
"""Returns the map needed for postprocessing (py_id -> plc_name)."""
|
||||||
return self.py_id_to_plc.copy()
|
return self.py_id_to_plc.copy()
|
||||||
|
|
||||||
|
|
||||||
# Helper function to extract PLC variable name from JSON operand info
|
# Helper function to extract PLC variable name from JSON operand info
|
||||||
def extract_plc_variable_name(operand_info):
|
def extract_plc_variable_name(operand_info):
|
||||||
if operand_info and operand_info.get("type") == "variable":
|
if operand_info and operand_info.get("type") == "variable":
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
// FB1809
|
||||||
|
// Block Type: FB
|
||||||
|
// Block Name (Original): SyrBrix Autocorrection
|
||||||
|
// Block Number: 1809
|
||||||
|
// Original Network Languages: LAD
|
||||||
|
// Block Comment:
|
||||||
|
// Syrup Autocorrection means that the measured syrup brix AND syrup density from
|
||||||
|
// meter, are used instead
|
||||||
|
// OF the one from the recipe, TO calculate the volumetric ratio.
|
||||||
|
// Activated only IF the beverage is sugar based.
|
||||||
|
|
||||||
|
FUNCTION_BLOCK "SyrBrix_Autocorrection"
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_INPUT
|
||||||
|
i_Value : Real;
|
||||||
|
i_Num : Int;
|
||||||
|
i_Enable : Bool;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_OUTPUT
|
||||||
|
FilterOut : Real;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_STAT
|
||||||
|
mProdSyrFact : Real;
|
||||||
|
mSyrMFMFact : Real;
|
||||||
|
mAuxONS : Bool;
|
||||||
|
mAuxONS1 : Bool;
|
||||||
|
mAuxONS2 : Bool;
|
||||||
|
mSyrBrix_AutoCorrReqTPON : Bool;
|
||||||
|
Syrup_Fact_Fltd : "LowPassFilter";
|
||||||
|
SyrupMFM_Fact_Fltd : "LowPassFilter";
|
||||||
|
mSyrBrix_AutoCorrReqTP : "TP:v1.0";
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
Latch_ONS : Bool;
|
||||||
|
sec2_ONS : Bool;
|
||||||
|
mProdSyrFactAcq : Bool;
|
||||||
|
mZeroTest : Bool;
|
||||||
|
mZeroTest1 : Bool;
|
||||||
|
SyrBrix : Real;
|
||||||
|
SyrBrixMaxCorr : Real;
|
||||||
|
SyrBrixMaxValveOp : Real;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
// Network 1: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Qualifier" := "gBlenderProdMode" AND "Blender_Variables_Pers"."gSugarBeverage" AND "Procedure_Variables"."First_Production"."Done" AND "gBlenderSuppliesOk" AND NOT "Blender_Variables_Pers"."gWaterRecipe" AND NOT "gBlenderRinseMode";
|
||||||
|
|
||||||
|
// Network 2: SyrBrix_AutoCorrReq (Original Language: LAD)
|
||||||
|
|
||||||
|
// PBox SymPy processed, logic in consumer
|
||||||
|
"SyrAutoCorrReq" := "HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch"; // P_TRIG("HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch") - Mem: "SyrAutoCorrReq"
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Request" := ("Procedure_Variables"."Syr_RunOut"."Latch" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch") OR ("HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "SyrAutoCorrReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch");
|
||||||
|
|
||||||
|
// Network 3: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Reset" := NOT "Procedure_Variables"."SyrAuto_Corr"."Qualifier";
|
||||||
|
|
||||||
|
// Network 4: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Wait" := NOT "gBlenderEnToRamp" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" AND "mPDS_SYR_PA_Data"."Input_From_mPDS"."gPAmPDS_CommErr") OR ("gFTP302_Fault" AND NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter");
|
||||||
|
|
||||||
|
// Network 5: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Latch" := ("Procedure_Variables"."SyrAuto_Corr"."Request" AND NOT "AUX Start CPU" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Done" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Reset" AND NOT "Procedure_Variables"."Syr_RunOut"."Done") OR ("Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "AUX Start CPU" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Done" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Reset" AND NOT "Procedure_Variables"."Syr_RunOut"."Done");
|
||||||
|
|
||||||
|
// Network 6: MIX - (Original Language: LAD)
|
||||||
|
|
||||||
|
// Edge Logic handled by Coil 28_dup4
|
||||||
|
"SyrAutoCorrLatch" := "Procedure_Variables"."SyrAuto_Corr"."Latch"; // P_TRIG("Procedure_Variables"."SyrAuto_Corr"."Latch") - Mem: "SyrAutoCorrLatch"
|
||||||
|
|
||||||
|
"Latch_ONS" := "Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "SyrAutoCorrLatch";
|
||||||
|
"SyrAutoCorrLatch" := "Procedure_Variables"."SyrAuto_Corr"."Latch"; // P_TRIG("Procedure_Variables"."SyrAuto_Corr"."Latch") - Mem: "SyrAutoCorrLatch"
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Running" := "Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Wait";
|
||||||
|
|
||||||
|
// Network 7: (Original Language: LAD)
|
||||||
|
|
||||||
|
SyrBrix_SyrupCorrPerc();
|
||||||
|
|
||||||
|
// Network 8: MIX - Blender Variables - Persistent (Original Language: LAD)
|
||||||
|
|
||||||
|
// Edge Logic handled by Coil 26_dup1
|
||||||
|
"SyrAutoCorrBlink2Sec" := "AUX Blink_2.0S"; // P_TRIG("AUX Blink_2.0S") - Mem: "SyrAutoCorrBlink2Sec"
|
||||||
|
|
||||||
|
"sec2_ONS" := "AUX Blink_2.0S" AND NOT "SyrAutoCorrBlink2Sec";
|
||||||
|
"SyrAutoCorrBlink2Sec" := "AUX Blink_2.0S"; // P_TRIG("AUX Blink_2.0S") - Mem: "SyrAutoCorrBlink2Sec"
|
||||||
|
|
||||||
|
// Network 9: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mProdSyrFactAcq" := "gBlenderEnToRamp" AND "gPV_SyrBrixOk" AND "sec2_ONS" AND "Procedure_Variables"."First_Production"."Done" AND "Procedure_Variables"."SyrAuto_Corr"."Qualifier";
|
||||||
|
|
||||||
|
// Network 10: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mZeroTest" := Eq("mProdSyrFact", 0) OR Eq("Blender_Variables"."gProdRunSyrFact", 0);
|
||||||
|
|
||||||
|
// Network 11: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mZeroTest1" := Eq("mSyrMFMFact", 0) OR Eq("Blender_Variables"."gProdRunSyrMFMFact", 0);
|
||||||
|
|
||||||
|
// Network 12: (Original Language: LAD)
|
||||||
|
// This segment calculates the Syrup Factor during the production, so when the
|
||||||
|
// Surup Run Out starts OR the Autocorrection is activated, the actual syrup brix
|
||||||
|
// doesn't change, the actual ratio doesn't change too
|
||||||
|
|
||||||
|
SEL_R(G := Eq("Blender_Variables"."gMeterSyrBrix", 0.0), IN0 := "Blender_Variables"."gMeterSyrBrix", IN1 := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix");
|
||||||
|
|
||||||
|
"SyrBrix" := "SyrBrix" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
|
||||||
|
"SyrBrix" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" / "SyrBrix";
|
||||||
|
|
||||||
|
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" AND "mProdSyrFactAcq" AND NOT "mZeroTest" THEN
|
||||||
|
SEL_R(G := "Procedure_Variables"."Syr_RunOut"."Latch" OR "Procedure_Variables"."SyrAuto_Corr"."Latch", IN0 := "SyrBrix", IN1 := "mProdSyrFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 13: (Original Language: LAD)
|
||||||
|
// This segment calculates the Syrup Factor during production, so when the Syrup
|
||||||
|
// Run Out starts OR the Autocorrection is activated, the actual syrup brix
|
||||||
|
// doesn't change, the actual ratio doesn't change too
|
||||||
|
|
||||||
|
SEL_R(G := Eq("Profibus_Variables"."gFTP302_Brix", 0.0), IN0 := "Profibus_Variables"."gFTP302_Brix", IN1 := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix");
|
||||||
|
|
||||||
|
"SyrBrix" := "SyrBrix" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
|
||||||
|
"SyrBrix" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" / "SyrBrix";
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "mZeroTest1" THEN
|
||||||
|
SEL_R(G := "Procedure_Variables"."Syr_RunOut"."Latch" OR "Procedure_Variables"."SyrAuto_Corr"."Latch", IN0 := "SyrBrix", IN1 := "mSyrMFMFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 14: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mZeroTest" OR "Procedure_Variables"."First_Production"."Latch" OR "gSyrBrixOutSpec_Fault" OR "gBlenderCIPMode" OR "gBlenderRinseMode" THEN
|
||||||
|
"mProdSyrFact" := 1.0;
|
||||||
|
"Blender_Variables"."gProdRunSyrFact" := 1.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 15: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mZeroTest1" OR "Procedure_Variables"."First_Production"."Latch" OR "gSyrBrixOutSpec_Fault" THEN
|
||||||
|
"mSyrMFMFact" := 1.0;
|
||||||
|
"Blender_Variables"."gProdRunSyrMFMFact" := 1.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 16: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"Syrup_Fact_Fltd"(i_Enable := "AUX TRUE", i_Num := 12, i_Value := "mProdSyrFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 17: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"SyrupMFM_Fact_Fltd"(i_Enable := "AUX TRUE", i_Num := 12, i_Value := "mSyrMFMFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 18: (Original Language: LAD)
|
||||||
|
// ??
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."SyrAuto_Corr"."Request" AND "AUX FALSE" THEN
|
||||||
|
"HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor" := "Blender_Variables"."gProdRunSyrFact" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"HMI_Variables_Cmd"."Recipe_Updates"."SyrFactUpdate" := "Procedure_Variables"."SyrAuto_Corr"."Request" AND "AUX FALSE";
|
||||||
|
|
||||||
|
// Network 19: MIX - Maximum Syrup Brix Autocorr Acheaved - minimum ratio - (Original Language: LAD)
|
||||||
|
|
||||||
|
"gMinRatio" := "HMI_PID"."RMP302"."Out" > 80.0;
|
||||||
|
|
||||||
|
// Network 20: MIX - Maximum Syrup Brix Autocorr Acheaved maximum autocorr per (Original Language: LAD)
|
||||||
|
// Creato due parametri per la Massima Correzzione.
|
||||||
|
// per la Produzione con Brix Sciroppo inferiori a 15 la massima correzzione
|
||||||
|
// passada 40 a 10. W.O.28/01/2025
|
||||||
|
|
||||||
|
"M1743.5" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" <= 15.0;
|
||||||
|
|
||||||
|
IF "AUX TRUE" AND NOT "M_validat_27_01_25" AND NOT "M1743.5" THEN
|
||||||
|
"SyrBrixMaxCorr" := 40.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF "AUX TRUE" AND "M1743.5" AND NOT "M_validat_27_01_25" THEN
|
||||||
|
"SyrBrixMaxCorr" := 10.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"gMaxSyrAutoCorrDone" := "HMI_Variables_Status"."Analog_Values"."SyrupBrixCorrection" > "SyrBrixMaxCorr";
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Status__8_ := "HMI_Variables_Status"."Analog_Values"."SyrupBrixCorrection" > "SyrBrixMaxCorr";
|
||||||
|
|
||||||
|
// Network 21: MIX - Maximum Syrup Brix Autocorr Acheaved - minimum ratio - (Original Language: LAD)
|
||||||
|
|
||||||
|
IF NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"gMinRatio" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"gMaxSyrAutoCorrDone" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 22: (Original Language: LAD)
|
||||||
|
|
||||||
|
"HMI_Variables_Status"."Procedures"."SyrBrixAutoRun" := "Procedure_Variables"."SyrAuto_Corr"."Latch";
|
||||||
|
|
||||||
|
// Network 23: Syrup Autocorrection Running (Original Language: LAD)
|
||||||
|
// Message Syrup Autocorrection Running TO HMI
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Status__4_ := "Procedure_Variables"."SyrAuto_Corr"."Running";
|
||||||
|
|
||||||
|
// Network 24: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Done" := ("Procedure_Variables"."SyrAuto_Corr"."Running" AND "gMinRatio" AND "Procedure_Variables"."Syr_RunOut"."Latch") OR ("Procedure_Variables"."SyrAuto_Corr"."Running" AND "gMaxSyrAutoCorrDone" AND "Procedure_Variables"."Syr_RunOut"."Latch") OR ("Procedure_Variables"."SyrAuto_Corr"."Request" AND NOT "Latch_ONS" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch");
|
||||||
|
|
||||||
|
END_FUNCTION_BLOCK
|
|
@ -0,0 +1,219 @@
|
||||||
|
// FB1809
|
||||||
|
// Block Type: FB
|
||||||
|
// Block Name (Original): SyrBrix Autocorrection
|
||||||
|
// Block Number: 1809
|
||||||
|
// Original Network Languages: LAD
|
||||||
|
// Block Comment:
|
||||||
|
// Syrup Autocorrection means that the measured syrup brix AND syrup density from
|
||||||
|
// meter, are used instead
|
||||||
|
// OF the one from the recipe, TO calculate the volumetric ratio.
|
||||||
|
// Activated only IF the beverage is sugar based.
|
||||||
|
|
||||||
|
FUNCTION_BLOCK "SyrBrix_Autocorrection"
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_INPUT
|
||||||
|
i_Value : Real;
|
||||||
|
i_Num : Int;
|
||||||
|
i_Enable : Bool;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_OUTPUT
|
||||||
|
FilterOut : Real;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_STAT
|
||||||
|
mProdSyrFact : Real;
|
||||||
|
mSyrMFMFact : Real;
|
||||||
|
mAuxONS : Bool;
|
||||||
|
mAuxONS1 : Bool;
|
||||||
|
mAuxONS2 : Bool;
|
||||||
|
mSyrBrix_AutoCorrReqTPON : Bool;
|
||||||
|
Syrup_Fact_Fltd : "LowPassFilter";
|
||||||
|
SyrupMFM_Fact_Fltd : "LowPassFilter";
|
||||||
|
mSyrBrix_AutoCorrReqTP : "TP:v1.0";
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
Latch_ONS : Bool;
|
||||||
|
sec2_ONS : Bool;
|
||||||
|
mProdSyrFactAcq : Bool;
|
||||||
|
mZeroTest : Bool;
|
||||||
|
mZeroTest1 : Bool;
|
||||||
|
SyrBrix : Real;
|
||||||
|
SyrBrixMaxCorr : Real;
|
||||||
|
SyrBrixMaxValveOp : Real;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
// Network 1: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Qualifier" := "gBlenderProdMode" AND "Blender_Variables_Pers"."gSugarBeverage" AND "Procedure_Variables"."First_Production"."Done" AND "gBlenderSuppliesOk" AND NOT "Blender_Variables_Pers"."gWaterRecipe" AND NOT "gBlenderRinseMode";
|
||||||
|
|
||||||
|
// Network 2: SyrBrix_AutoCorrReq (Original Language: LAD)
|
||||||
|
|
||||||
|
// PBox SymPy processed, logic in consumer
|
||||||
|
"SyrAutoCorrReq" := "HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch"; // P_TRIG("HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch") - Mem: "SyrAutoCorrReq"
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Request" := ("Procedure_Variables"."Syr_RunOut"."Latch" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch") OR ("HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "SyrAutoCorrReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch");
|
||||||
|
|
||||||
|
// Network 3: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Reset" := NOT "Procedure_Variables"."SyrAuto_Corr"."Qualifier";
|
||||||
|
|
||||||
|
// Network 4: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Wait" := NOT "gBlenderEnToRamp" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" AND "mPDS_SYR_PA_Data"."Input_From_mPDS"."gPAmPDS_CommErr") OR ("gFTP302_Fault" AND NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter");
|
||||||
|
|
||||||
|
// Network 5: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Latch" := ("Procedure_Variables"."SyrAuto_Corr"."Request" AND NOT "AUX Start CPU" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Done" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Reset" AND NOT "Procedure_Variables"."Syr_RunOut"."Done") OR ("Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "AUX Start CPU" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Done" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Reset" AND NOT "Procedure_Variables"."Syr_RunOut"."Done");
|
||||||
|
|
||||||
|
// Network 6: MIX - (Original Language: LAD)
|
||||||
|
|
||||||
|
// Edge Logic handled by Coil 28_dup4
|
||||||
|
"SyrAutoCorrLatch" := "Procedure_Variables"."SyrAuto_Corr"."Latch"; // P_TRIG("Procedure_Variables"."SyrAuto_Corr"."Latch") - Mem: "SyrAutoCorrLatch"
|
||||||
|
|
||||||
|
"SyrAutoCorrLatch" := "Procedure_Variables"."SyrAuto_Corr"."Latch";; // P_TRIG("Procedure_Variables"."SyrAuto_Corr"."Latch") - Mem: "SyrAutoCorrLatch"
|
||||||
|
"Latch_ONS" := "Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "SyrAutoCorrLatch";
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Running" := "Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Wait";
|
||||||
|
|
||||||
|
// Network 7: (Original Language: LAD)
|
||||||
|
|
||||||
|
SyrBrix_SyrupCorrPerc();
|
||||||
|
|
||||||
|
// Network 8: MIX - Blender Variables - Persistent (Original Language: LAD)
|
||||||
|
|
||||||
|
// Edge Logic handled by Coil 26_dup1
|
||||||
|
"SyrAutoCorrBlink2Sec" := "AUX Blink_2.0S"; // P_TRIG("AUX Blink_2.0S") - Mem: "SyrAutoCorrBlink2Sec"
|
||||||
|
|
||||||
|
"SyrAutoCorrBlink2Sec" := "AUX Blink_2.0S";; // P_TRIG("AUX Blink_2.0S") - Mem: "SyrAutoCorrBlink2Sec"
|
||||||
|
"sec2_ONS" := "AUX Blink_2.0S" AND NOT "SyrAutoCorrBlink2Sec";
|
||||||
|
|
||||||
|
// Network 9: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mProdSyrFactAcq" := "gBlenderEnToRamp" AND "gPV_SyrBrixOk" AND "sec2_ONS" AND "Procedure_Variables"."First_Production"."Done" AND "Procedure_Variables"."SyrAuto_Corr"."Qualifier";
|
||||||
|
|
||||||
|
// Network 10: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mZeroTest" := Eq("mProdSyrFact", 0) OR Eq("Blender_Variables"."gProdRunSyrFact", 0);
|
||||||
|
|
||||||
|
// Network 11: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mZeroTest1" := Eq("mSyrMFMFact", 0) OR Eq("Blender_Variables"."gProdRunSyrMFMFact", 0);
|
||||||
|
|
||||||
|
// Network 12: (Original Language: LAD)
|
||||||
|
// This segment calculates the Syrup Factor during the production, so when the
|
||||||
|
// Surup Run Out starts OR the Autocorrection is activated, the actual syrup brix
|
||||||
|
// doesn't change, the actual ratio doesn't change too
|
||||||
|
|
||||||
|
SEL_R(G := Eq("Blender_Variables"."gMeterSyrBrix", 0.0), IN0 := "Blender_Variables"."gMeterSyrBrix", IN1 := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix");
|
||||||
|
|
||||||
|
"SyrBrix" := "SyrBrix" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
|
||||||
|
"SyrBrix" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" / "SyrBrix";
|
||||||
|
|
||||||
|
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" AND "mProdSyrFactAcq" AND NOT "mZeroTest" THEN
|
||||||
|
SEL_R(G := "Procedure_Variables"."Syr_RunOut"."Latch" OR "Procedure_Variables"."SyrAuto_Corr"."Latch", IN0 := "SyrBrix", IN1 := "mProdSyrFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 13: (Original Language: LAD)
|
||||||
|
// This segment calculates the Syrup Factor during production, so when the Syrup
|
||||||
|
// Run Out starts OR the Autocorrection is activated, the actual syrup brix
|
||||||
|
// doesn't change, the actual ratio doesn't change too
|
||||||
|
|
||||||
|
SEL_R(G := Eq("Profibus_Variables"."gFTP302_Brix", 0.0), IN0 := "Profibus_Variables"."gFTP302_Brix", IN1 := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix");
|
||||||
|
|
||||||
|
"SyrBrix" := "SyrBrix" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
|
||||||
|
"SyrBrix" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" / "SyrBrix";
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "mZeroTest1" THEN
|
||||||
|
SEL_R(G := "Procedure_Variables"."Syr_RunOut"."Latch" OR "Procedure_Variables"."SyrAuto_Corr"."Latch", IN0 := "SyrBrix", IN1 := "mSyrMFMFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 14: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mZeroTest" OR "Procedure_Variables"."First_Production"."Latch" OR "gSyrBrixOutSpec_Fault" OR "gBlenderCIPMode" OR "gBlenderRinseMode" THEN
|
||||||
|
"mProdSyrFact" := 1.0;
|
||||||
|
"Blender_Variables"."gProdRunSyrFact" := 1.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 15: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mZeroTest1" OR "Procedure_Variables"."First_Production"."Latch" OR "gSyrBrixOutSpec_Fault" THEN
|
||||||
|
"mSyrMFMFact" := 1.0;
|
||||||
|
"Blender_Variables"."gProdRunSyrMFMFact" := 1.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 16: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"Syrup_Fact_Fltd"(i_Enable := "AUX TRUE", i_Num := 12, i_Value := "mProdSyrFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 17: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"SyrupMFM_Fact_Fltd"(i_Enable := "AUX TRUE", i_Num := 12, i_Value := "mSyrMFMFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 18: (Original Language: LAD)
|
||||||
|
// ??
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."SyrAuto_Corr"."Request" AND "AUX FALSE" THEN
|
||||||
|
"HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor" := "Blender_Variables"."gProdRunSyrFact" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"HMI_Variables_Cmd"."Recipe_Updates"."SyrFactUpdate" := "Procedure_Variables"."SyrAuto_Corr"."Request" AND "AUX FALSE";
|
||||||
|
|
||||||
|
// Network 19: MIX - Maximum Syrup Brix Autocorr Acheaved - minimum ratio - (Original Language: LAD)
|
||||||
|
|
||||||
|
"gMinRatio" := "HMI_PID"."RMP302"."Out" > 80.0;
|
||||||
|
|
||||||
|
// Network 20: MIX - Maximum Syrup Brix Autocorr Acheaved maximum autocorr per (Original Language: LAD)
|
||||||
|
// Creato due parametri per la Massima Correzzione.
|
||||||
|
// per la Produzione con Brix Sciroppo inferiori a 15 la massima correzzione
|
||||||
|
// passada 40 a 10. W.O.28/01/2025
|
||||||
|
|
||||||
|
"M1743.5" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" <= 15.0;
|
||||||
|
|
||||||
|
IF "AUX TRUE" AND NOT "M_validat_27_01_25" AND NOT "M1743.5" THEN
|
||||||
|
"SyrBrixMaxCorr" := 40.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF "AUX TRUE" AND "M1743.5" AND NOT "M_validat_27_01_25" THEN
|
||||||
|
"SyrBrixMaxCorr" := 10.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"gMaxSyrAutoCorrDone" := "HMI_Variables_Status"."Analog_Values"."SyrupBrixCorrection" > "SyrBrixMaxCorr";
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Status__8_ := "HMI_Variables_Status"."Analog_Values"."SyrupBrixCorrection" > "SyrBrixMaxCorr";
|
||||||
|
|
||||||
|
// Network 21: MIX - Maximum Syrup Brix Autocorr Acheaved - minimum ratio - (Original Language: LAD)
|
||||||
|
|
||||||
|
IF NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"gMinRatio" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"gMaxSyrAutoCorrDone" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 22: (Original Language: LAD)
|
||||||
|
|
||||||
|
"HMI_Variables_Status"."Procedures"."SyrBrixAutoRun" := "Procedure_Variables"."SyrAuto_Corr"."Latch";
|
||||||
|
|
||||||
|
// Network 23: Syrup Autocorrection Running (Original Language: LAD)
|
||||||
|
// Message Syrup Autocorrection Running TO HMI
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Status__4_ := "Procedure_Variables"."SyrAuto_Corr"."Running";
|
||||||
|
|
||||||
|
// Network 24: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Done" := ("Procedure_Variables"."SyrAuto_Corr"."Running" AND "gMinRatio" AND "Procedure_Variables"."Syr_RunOut"."Latch") OR ("Procedure_Variables"."SyrAuto_Corr"."Running" AND "gMaxSyrAutoCorrDone" AND "Procedure_Variables"."Syr_RunOut"."Latch") OR ("Procedure_Variables"."SyrAuto_Corr"."Request" AND NOT "Latch_ONS" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch");
|
||||||
|
|
||||||
|
END_FUNCTION_BLOCK
|
|
@ -0,0 +1,219 @@
|
||||||
|
// FB1809
|
||||||
|
// Block Type: FB
|
||||||
|
// Block Name (Original): SyrBrix Autocorrection
|
||||||
|
// Block Number: 1809
|
||||||
|
// Original Network Languages: LAD
|
||||||
|
// Block Comment:
|
||||||
|
// Syrup Autocorrection means that the measured syrup brix AND syrup density from
|
||||||
|
// meter, are used instead
|
||||||
|
// OF the one from the recipe, TO calculate the volumetric ratio.
|
||||||
|
// Activated only IF the beverage is sugar based.
|
||||||
|
|
||||||
|
FUNCTION_BLOCK "SyrBrix_Autocorrection"
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_INPUT
|
||||||
|
i_Value : Real;
|
||||||
|
i_Num : Int;
|
||||||
|
i_Enable : Bool;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_OUTPUT
|
||||||
|
FilterOut : Real;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_STAT
|
||||||
|
mProdSyrFact : Real;
|
||||||
|
mSyrMFMFact : Real;
|
||||||
|
mAuxONS : Bool;
|
||||||
|
mAuxONS1 : Bool;
|
||||||
|
mAuxONS2 : Bool;
|
||||||
|
mSyrBrix_AutoCorrReqTPON : Bool;
|
||||||
|
Syrup_Fact_Fltd : "LowPassFilter";
|
||||||
|
SyrupMFM_Fact_Fltd : "LowPassFilter";
|
||||||
|
mSyrBrix_AutoCorrReqTP : "TP:v1.0";
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
Latch_ONS : Bool;
|
||||||
|
sec2_ONS : Bool;
|
||||||
|
mProdSyrFactAcq : Bool;
|
||||||
|
mZeroTest : Bool;
|
||||||
|
mZeroTest1 : Bool;
|
||||||
|
SyrBrix : Real;
|
||||||
|
SyrBrixMaxCorr : Real;
|
||||||
|
SyrBrixMaxValveOp : Real;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
// Network 1: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Qualifier" := "gBlenderProdMode" AND "Blender_Variables_Pers"."gSugarBeverage" AND "Procedure_Variables"."First_Production"."Done" AND "gBlenderSuppliesOk" AND NOT "Blender_Variables_Pers"."gWaterRecipe" AND NOT "gBlenderRinseMode";
|
||||||
|
|
||||||
|
// Network 2: SyrBrix_AutoCorrReq (Original Language: LAD)
|
||||||
|
|
||||||
|
// PBox SymPy processed, logic in consumer
|
||||||
|
"SyrAutoCorrReq" := "HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch"; // P_TRIG("HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch") - Mem: "SyrAutoCorrReq"
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Request" := ("Procedure_Variables"."Syr_RunOut"."Latch" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch") OR ("HMI_Variables_Cmd"."Commands_From_HMI"."CMD_SyrAutoReq" AND NOT "SyrAutoCorrReq" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch");
|
||||||
|
|
||||||
|
// Network 3: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Reset" := NOT "Procedure_Variables"."SyrAuto_Corr"."Qualifier";
|
||||||
|
|
||||||
|
// Network 4: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Wait" := NOT "gBlenderEnToRamp" OR ("HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" AND "mPDS_SYR_PA_Data"."Input_From_mPDS"."gPAmPDS_CommErr") OR ("gFTP302_Fault" AND NOT "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter");
|
||||||
|
|
||||||
|
// Network 5: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Latch" := ("Procedure_Variables"."SyrAuto_Corr"."Request" AND NOT "AUX Start CPU" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Done" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Reset" AND NOT "Procedure_Variables"."Syr_RunOut"."Done") OR ("Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "AUX Start CPU" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Done" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Reset" AND NOT "Procedure_Variables"."Syr_RunOut"."Done");
|
||||||
|
|
||||||
|
// Network 6: MIX - (Original Language: LAD)
|
||||||
|
|
||||||
|
// Edge Logic handled by Coil 28_dup4
|
||||||
|
"SyrAutoCorrLatch" := "Procedure_Variables"."SyrAuto_Corr"."Latch"; // P_TRIG("Procedure_Variables"."SyrAuto_Corr"."Latch") - Mem: "SyrAutoCorrLatch"
|
||||||
|
|
||||||
|
"SyrAutoCorrLatch" := "Procedure_Variables"."SyrAuto_Corr"."Latch"; // P_TRIG("Procedure_Variables"."SyrAuto_Corr"."Latch") - Mem: "SyrAutoCorrLatch"
|
||||||
|
"Latch_ONS" := "Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "SyrAutoCorrLatch";
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Running" := "Procedure_Variables"."SyrAuto_Corr"."Latch" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Wait";
|
||||||
|
|
||||||
|
// Network 7: (Original Language: LAD)
|
||||||
|
|
||||||
|
SyrBrix_SyrupCorrPerc();
|
||||||
|
|
||||||
|
// Network 8: MIX - Blender Variables - Persistent (Original Language: LAD)
|
||||||
|
|
||||||
|
// Edge Logic handled by Coil 26_dup1
|
||||||
|
"SyrAutoCorrBlink2Sec" := "AUX Blink_2.0S"; // P_TRIG("AUX Blink_2.0S") - Mem: "SyrAutoCorrBlink2Sec"
|
||||||
|
|
||||||
|
"SyrAutoCorrBlink2Sec" := "AUX Blink_2.0S"; // P_TRIG("AUX Blink_2.0S") - Mem: "SyrAutoCorrBlink2Sec"
|
||||||
|
"sec2_ONS" := "AUX Blink_2.0S" AND NOT "SyrAutoCorrBlink2Sec";
|
||||||
|
|
||||||
|
// Network 9: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mProdSyrFactAcq" := "gBlenderEnToRamp" AND "gPV_SyrBrixOk" AND "sec2_ONS" AND "Procedure_Variables"."First_Production"."Done" AND "Procedure_Variables"."SyrAuto_Corr"."Qualifier";
|
||||||
|
|
||||||
|
// Network 10: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mZeroTest" := Eq("mProdSyrFact", 0) OR Eq("Blender_Variables"."gProdRunSyrFact", 0);
|
||||||
|
|
||||||
|
// Network 11: (Original Language: LAD)
|
||||||
|
|
||||||
|
"mZeroTest1" := Eq("mSyrMFMFact", 0) OR Eq("Blender_Variables"."gProdRunSyrMFMFact", 0);
|
||||||
|
|
||||||
|
// Network 12: (Original Language: LAD)
|
||||||
|
// This segment calculates the Syrup Factor during the production, so when the
|
||||||
|
// Surup Run Out starts OR the Autocorrection is activated, the actual syrup brix
|
||||||
|
// doesn't change, the actual ratio doesn't change too
|
||||||
|
|
||||||
|
SEL_R(G := Eq("Blender_Variables"."gMeterSyrBrix", 0.0), IN0 := "Blender_Variables"."gMeterSyrBrix", IN1 := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix");
|
||||||
|
|
||||||
|
"SyrBrix" := "SyrBrix" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
|
||||||
|
"SyrBrix" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" / "SyrBrix";
|
||||||
|
|
||||||
|
IF "HMI_Blender_Parameters"."Processor_Options"."Blender_OPT"."_SyrBrixMeter" AND "mProdSyrFactAcq" AND NOT "mZeroTest" THEN
|
||||||
|
SEL_R(G := "Procedure_Variables"."Syr_RunOut"."Latch" OR "Procedure_Variables"."SyrAuto_Corr"."Latch", IN0 := "SyrBrix", IN1 := "mProdSyrFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 13: (Original Language: LAD)
|
||||||
|
// This segment calculates the Syrup Factor during production, so when the Syrup
|
||||||
|
// Run Out starts OR the Autocorrection is activated, the actual syrup brix
|
||||||
|
// doesn't change, the actual ratio doesn't change too
|
||||||
|
|
||||||
|
SEL_R(G := Eq("Profibus_Variables"."gFTP302_Brix", 0.0), IN0 := "Profibus_Variables"."gFTP302_Brix", IN1 := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix");
|
||||||
|
|
||||||
|
"SyrBrix" := "SyrBrix" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
|
||||||
|
"SyrBrix" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" / "SyrBrix";
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "mZeroTest1" THEN
|
||||||
|
SEL_R(G := "Procedure_Variables"."Syr_RunOut"."Latch" OR "Procedure_Variables"."SyrAuto_Corr"."Latch", IN0 := "SyrBrix", IN1 := "mSyrMFMFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 14: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mZeroTest" OR "Procedure_Variables"."First_Production"."Latch" OR "gSyrBrixOutSpec_Fault" OR "gBlenderCIPMode" OR "gBlenderRinseMode" THEN
|
||||||
|
"mProdSyrFact" := 1.0;
|
||||||
|
"Blender_Variables"."gProdRunSyrFact" := 1.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 15: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mZeroTest1" OR "Procedure_Variables"."First_Production"."Latch" OR "gSyrBrixOutSpec_Fault" THEN
|
||||||
|
"mSyrMFMFact" := 1.0;
|
||||||
|
"Blender_Variables"."gProdRunSyrMFMFact" := 1.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 16: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"Syrup_Fact_Fltd"(i_Enable := "AUX TRUE", i_Num := 12, i_Value := "mProdSyrFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 17: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "mProdSyrFactAcq" AND NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"SyrupMFM_Fact_Fltd"(i_Enable := "AUX TRUE", i_Num := 12, i_Value := "mSyrMFMFact");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 18: (Original Language: LAD)
|
||||||
|
// ??
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."SyrAuto_Corr"."Request" AND "AUX FALSE" THEN
|
||||||
|
"HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor" := "Blender_Variables"."gProdRunSyrFact" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"HMI_Variables_Cmd"."Recipe_Updates"."SyrFactUpdate" := "Procedure_Variables"."SyrAuto_Corr"."Request" AND "AUX FALSE";
|
||||||
|
|
||||||
|
// Network 19: MIX - Maximum Syrup Brix Autocorr Acheaved - minimum ratio - (Original Language: LAD)
|
||||||
|
|
||||||
|
"gMinRatio" := "HMI_PID"."RMP302"."Out" > 80.0;
|
||||||
|
|
||||||
|
// Network 20: MIX - Maximum Syrup Brix Autocorr Acheaved maximum autocorr per (Original Language: LAD)
|
||||||
|
// Creato due parametri per la Massima Correzzione.
|
||||||
|
// per la Produzione con Brix Sciroppo inferiori a 15 la massima correzzione
|
||||||
|
// passada 40 a 10. W.O.28/01/2025
|
||||||
|
|
||||||
|
"M1743.5" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" <= 15.0;
|
||||||
|
|
||||||
|
IF "AUX TRUE" AND NOT "M_validat_27_01_25" AND NOT "M1743.5" THEN
|
||||||
|
"SyrBrixMaxCorr" := 40.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF "AUX TRUE" AND "M1743.5" AND NOT "M_validat_27_01_25" THEN
|
||||||
|
"SyrBrixMaxCorr" := 10.0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"gMaxSyrAutoCorrDone" := "HMI_Variables_Status"."Analog_Values"."SyrupBrixCorrection" > "SyrBrixMaxCorr";
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Status__8_ := "HMI_Variables_Status"."Analog_Values"."SyrupBrixCorrection" > "SyrBrixMaxCorr";
|
||||||
|
|
||||||
|
// Network 21: MIX - Maximum Syrup Brix Autocorr Acheaved - minimum ratio - (Original Language: LAD)
|
||||||
|
|
||||||
|
IF NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"gMinRatio" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF NOT "Procedure_Variables"."SyrAuto_Corr"."Latch" THEN
|
||||||
|
"gMaxSyrAutoCorrDone" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 22: (Original Language: LAD)
|
||||||
|
|
||||||
|
"HMI_Variables_Status"."Procedures"."SyrBrixAutoRun" := "Procedure_Variables"."SyrAuto_Corr"."Latch";
|
||||||
|
|
||||||
|
// Network 23: Syrup Autocorrection Running (Original Language: LAD)
|
||||||
|
// Message Syrup Autocorrection Running TO HMI
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Status__4_ := "Procedure_Variables"."SyrAuto_Corr"."Running";
|
||||||
|
|
||||||
|
// Network 24: (Original Language: LAD)
|
||||||
|
|
||||||
|
"Procedure_Variables"."SyrAuto_Corr"."Done" := ("Procedure_Variables"."SyrAuto_Corr"."Running" AND "gMinRatio" AND "Procedure_Variables"."Syr_RunOut"."Latch") OR ("Procedure_Variables"."SyrAuto_Corr"."Running" AND "gMaxSyrAutoCorrDone" AND "Procedure_Variables"."Syr_RunOut"."Latch") OR ("Procedure_Variables"."SyrAuto_Corr"."Request" AND NOT "Latch_ONS" AND NOT "Procedure_Variables"."Syr_RunOut"."Latch");
|
||||||
|
|
||||||
|
END_FUNCTION_BLOCK
|
|
@ -0,0 +1,269 @@
|
||||||
|
// FB1813
|
||||||
|
// Block Type: FB
|
||||||
|
// Block Name (Original): Syrup Line MFM Prep DAR
|
||||||
|
// Block Number: 1813
|
||||||
|
// Original Network Languages: LAD, STL
|
||||||
|
|
||||||
|
FUNCTION_BLOCK "Syrup_Line_MFM_Prep_DAR"
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_INPUT
|
||||||
|
IN : Bool;
|
||||||
|
PT : Time;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_OUTPUT
|
||||||
|
Q : Bool;
|
||||||
|
ET : Time;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_STAT
|
||||||
|
mStepNum : Int;
|
||||||
|
mTimeStep : Int;
|
||||||
|
Real_Time : Time;
|
||||||
|
mTransition : Bool;
|
||||||
|
mSyrLineMFMPrepONS : Bool;
|
||||||
|
mSyrupLineManualDrainSR : Bool;
|
||||||
|
mQTM306_PrepReqTPON : Bool;
|
||||||
|
mQTM306_PrepReqTP1ON : Bool;
|
||||||
|
mDelayON_StopPumpON : Bool;
|
||||||
|
mDelayON_SyrupMinON : Bool;
|
||||||
|
mDelayON_PumpStatusON : Bool;
|
||||||
|
mHVP302_TONON : Bool;
|
||||||
|
mQTM306_Prep_TimeOutON : Bool;
|
||||||
|
mQTM306_PrepReqTP : "TP:v1.0";
|
||||||
|
mQTM306_PrepReqTP1 : "TP:v1.0";
|
||||||
|
mDelayON_StopPump : "TON:v1.0";
|
||||||
|
mDelayON_SyrupMin : "TON:v1.0";
|
||||||
|
mDelayON_PumpStatus : "TON:v1.0";
|
||||||
|
mHVP302_TON : "TON:v1.0";
|
||||||
|
mQTM306_Prep_TimeOut : "TON:v1.0";
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
mDummy : Bool;
|
||||||
|
mAux1 : Real;
|
||||||
|
mAux2 : Real;
|
||||||
|
mTimeOutElapsed : Bool;
|
||||||
|
mStopPumpP2 : Bool;
|
||||||
|
mSyrMinLevel : Bool;
|
||||||
|
mPumpP2Running : Bool;
|
||||||
|
mWaterCountAcheaved : Bool;
|
||||||
|
mSyrupLineManualDrained : Bool;
|
||||||
|
mFuzzyNetOut : Bool;
|
||||||
|
Out_Time_DI : DInt;
|
||||||
|
Real_Time_S5 : S5Time;
|
||||||
|
mProcSlctd : Bool;
|
||||||
|
mFuzzyNetAdd1 : Real;
|
||||||
|
mFuzzyNetAdd2 : Real;
|
||||||
|
mFuzzyNetAdd3 : Real;
|
||||||
|
mSyrBrixAux : Real;
|
||||||
|
mSyrBrixAux_1 : Real;
|
||||||
|
Aux_Somma_Lt : Real;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
#_1S : Bool; // Auto-generated temporary
|
||||||
|
#_4S : Bool; // Auto-generated temporary
|
||||||
|
#_4S_600MS : Bool; // Auto-generated temporary
|
||||||
|
#_5S : Bool; // Auto-generated temporary
|
||||||
|
#TON_INSTANCE_26_dup3 : Bool; // Auto-generated temporary
|
||||||
|
#TON_INSTANCE_26_dup5 : Bool; // Auto-generated temporary
|
||||||
|
#TON_INSTANCE_27_dup4 : Bool; // Auto-generated temporary
|
||||||
|
#TON_INSTANCE_30_dup5 : Bool; // Auto-generated temporary
|
||||||
|
#TP_INSTANCE_44 : Bool; // Auto-generated temporary
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
// Network 1: (Original Language: LAD)
|
||||||
|
|
||||||
|
%DB960.DBX56.0 := ("gBlenderProdMode" AND "gBlenderSuppliesOk" AND "System_RunOut_Variables"."FastChangeOverActivated" AND NOT "Blender_Variables_Pers"."gWaterRecipe") OR ("gBlenderProdMode" AND "gBlenderSuppliesOk" AND NOT "Blender_Variables_Pers"."gWaterRecipe" AND NOT "gBlenderRinseMode");
|
||||||
|
|
||||||
|
// Network 2: SyrLineMFMPrepReq (Original Language: LAD)
|
||||||
|
|
||||||
|
// PBox SymPy processed, logic in consumer
|
||||||
|
"Tag_69" := "HMI_Variables_Cmd"."Commands_From_HMI"."CMD_FTP302Line_Prep" AND NOT "System_RunOut_Variables"."FastChangeOverActivated" AND NOT "Procedure_Variables"."Syr_RunOut"."FastChangeOverRinseDone"; // P_TRIG("HMI_Variables_Cmd"."Commands_From_HMI"."CMD_FTP302Line_Prep" AND NOT "System_RunOut_Variables"."FastChangeOverActivated" AND NOT "Procedure_Variables"."Syr_RunOut"."FastChangeOverRinseDone") - Mem: "Tag_69"
|
||||||
|
|
||||||
|
#TP_INSTANCE_44(IN := "System_RunOut_Variables"."FastChangeOverActivated" AND "Procedure_Variables"."Syr_RunOut"."FastChangeOverRinseDone" AND "HMI_Variables_Cmd"."GLOBAL_CMD"."_EnableNextRecipe" AND "System_RunOut_Variables"."NextRecipeOk" AND NOT %DB960.DBX56.6, PT := T#1S); // TODO: Declarar #TP_INSTANCE_44 : TP;
|
||||||
|
|
||||||
|
%DB960.DBX56.1 := ("mQTM306_PrepReqTP1ON" AND %DB960.DBX56.0) OR (%DB960.DBX56.0 AND "HMI_Variables_Cmd"."Commands_From_HMI"."CMD_FTP302Line_Prep" AND NOT "System_RunOut_Variables"."FastChangeOverActivated" AND NOT "Tag_69" AND NOT "Procedure_Variables"."Syr_RunOut"."FastChangeOverRinseDone");
|
||||||
|
|
||||||
|
// Network 3: (Original Language: LAD)
|
||||||
|
|
||||||
|
// PBox SymPy processed, logic in consumer
|
||||||
|
"mSyrLineMFMPrepONS" := %DB960.DBX56.1 AND %DB960.DBX56.6 AND NOT "Procedure_Variables"."Blender_Run"."Latch" AND NOT "System_RunOut_Variables"."FastChangeOverActivated"; // P_TRIG(%DB960.DBX56.1 AND %DB960.DBX56.6 AND NOT "Procedure_Variables"."Blender_Run"."Latch" AND NOT "System_RunOut_Variables"."FastChangeOverActivated") - Mem: "mSyrLineMFMPrepONS"
|
||||||
|
|
||||||
|
%DB960.DBX56.2 := "gBlenderCIPMode" OR "Blender_Variables_Pers"."gWaterRecipe" OR ("gEmergencyPressed" AND %DB960.DBX56.3) OR ("Procedure_Variables"."SyrupLineRinse"."Latch" AND "System_RunOut_Variables"."FastChangeOverActivated") OR ("gBlenderRinseMode" AND NOT "System_RunOut_Variables"."FastChangeOverActivated") OR (%DB960.DBX56.1 AND %DB960.DBX56.6 AND NOT "Procedure_Variables"."Blender_Run"."Latch" AND NOT "System_RunOut_Variables"."FastChangeOverActivated" AND NOT "mSyrLineMFMPrepONS");
|
||||||
|
|
||||||
|
// Network 4: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF ("Procedure_Variables"."Blender_Rinse"."Latch" AND NOT "AUX MASTER VALIDATION") OR ("Procedure_Variables"."Syr_RunOut"."Latch" AND NOT "AUX MASTER VALIDATION") OR ("CIP_Program_Variables"."Status"."Started" AND NOT "AUX MASTER VALIDATION") THEN
|
||||||
|
%DB960.DBX57.0 := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 5: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."FTP302Line_Preparation"."Reset" THEN
|
||||||
|
"mStepNum" := 0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."FTP302Line_Preparation"."Reset" THEN
|
||||||
|
%DB960.DBX56.6 := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."FTP302Line_Preparation"."Reset" THEN
|
||||||
|
"Procedure_Variables"."FTP302Line_Preparation"."LinePrepared" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."FTP302Line_Preparation"."Reset" THEN
|
||||||
|
"mWaterCountAcheaved" := FALSE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 6: (Original Language: LAD)
|
||||||
|
|
||||||
|
%DB960.DBX56.5 := "HMI_Device"."PPP302"."Alarm" OR "HMI_Device"."SyrupRoom_SyrupPump"."Alarm" OR NOT "HMI_Digital"."PSM311"."Filtered";
|
||||||
|
|
||||||
|
// Network 7: (Original Language: LAD)
|
||||||
|
|
||||||
|
%DB960.DBX56.3 := (%DB960.DBX56.1 AND NOT "AUX Start CPU" AND NOT %DB960.DBX56.2 AND NOT %DB960.DBX56.6) OR ("Procedure_Variables"."FTP302Line_Preparation"."Latch" AND NOT "AUX Start CPU" AND NOT %DB960.DBX56.2 AND NOT %DB960.DBX56.6);
|
||||||
|
|
||||||
|
IF (%DB960.DBX56.1 AND NOT "AUX Start CPU" AND NOT %DB960.DBX56.2 AND NOT %DB960.DBX56.6) OR ("Procedure_Variables"."FTP302Line_Preparation"."Latch" AND NOT "AUX Start CPU" AND NOT %DB960.DBX56.2 AND NOT %DB960.DBX56.6) THEN
|
||||||
|
"HMI_Variables_Status"."Procedures"."BlenderStateNum" := 3;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 8: (Original Language: LAD)
|
||||||
|
|
||||||
|
%DB960.DBX56.4 := %DB960.DBX56.3 AND NOT %DB960.DBX56.5;
|
||||||
|
|
||||||
|
// Network 9: MIX - (Original Language: LAD)
|
||||||
|
|
||||||
|
"mAux1" := "Blender_Variables"."gMinProduction" / 6.0;
|
||||||
|
|
||||||
|
SEL_R(G := Ne("mAux1", 0.0), IN0 := 1.0, IN1 := "mAux1");
|
||||||
|
|
||||||
|
"mAux2" := "HMI_Blender_Parameters"."ProcessSetup"."_SyrupRunOutLiters" * 1.5;
|
||||||
|
|
||||||
|
"mAux1" := "mAux2" / "mAux1";
|
||||||
|
|
||||||
|
"Out_Time_DI" := CEIL("mAux1");
|
||||||
|
|
||||||
|
"mDummy" := TRUE;
|
||||||
|
|
||||||
|
// Network 10: (Original Language: STL)
|
||||||
|
// #Out_Time_DI (DINT) converted in #Real_Time_S5 (S5Time)
|
||||||
|
// Use L#1000 IF #Out_Time_DI is in ms
|
||||||
|
|
||||||
|
// --- BEGIN STL Network 10 ---
|
||||||
|
```stl
|
||||||
|
L "Out_Time_DI"
|
||||||
|
L 1000
|
||||||
|
MUL_D
|
||||||
|
T "Real_Time"
|
||||||
|
```
|
||||||
|
// --- END STL Network 10 ---
|
||||||
|
|
||||||
|
// Network 11: SyrLineMFMPrep_TimeOut (Original Language: LAD)
|
||||||
|
|
||||||
|
#TON_INSTANCE_26_dup3(IN := %DBX56.3, PT := "Real_Time"); // TODO: Declarar #TON_INSTANCE_26_dup3 : TON;
|
||||||
|
|
||||||
|
"mTimeOutElapsed" := "mQTM306_Prep_TimeOutON";
|
||||||
|
|
||||||
|
// Network 12: DelayON_StopPump (Original Language: LAD)
|
||||||
|
|
||||||
|
#TON_INSTANCE_27_dup4(IN := NOT "gIN_SyrTank_MinLvl", PT := T#4S_600MS); // TODO: Declarar #TON_INSTANCE_27_dup4 : TON;
|
||||||
|
|
||||||
|
"mStopPumpP2" := "mDelayON_StopPumpON";
|
||||||
|
|
||||||
|
// Network 13: DelayON_SyrupMin (Original Language: LAD)
|
||||||
|
|
||||||
|
"mSyrMinLevel" := "gIN_SyrTank_MinLvl";
|
||||||
|
|
||||||
|
// Network 14: DelayON_PumpStatus (Original Language: LAD)
|
||||||
|
|
||||||
|
#TON_INSTANCE_26_dup5(IN := "HMI_Device"."PPP302"."Out", PT := T#4S); // TODO: Declarar #TON_INSTANCE_26_dup5 : TON;
|
||||||
|
|
||||||
|
"mPumpP2Running" := "mDelayON_PumpStatusON";
|
||||||
|
|
||||||
|
// Network 15: SYRUP LINE MANUAL DRAIN (Original Language: LAD)
|
||||||
|
// THIS PROCEDURE HAS TO BE DONE BEFORE TO SELECT THE SYRUP LINE STARTUP.
|
||||||
|
|
||||||
|
#TON_INSTANCE_30_dup5(IN := "gIN_HVP301_Aux", PT := T#5S); // TODO: Declarar #TON_INSTANCE_30_dup5 : TON;
|
||||||
|
|
||||||
|
// Network 16: MIX - HMI Variables Cmd (Original Language: LAD)
|
||||||
|
|
||||||
|
"mSyrupLineManualDrained" := %DB960.DBX56.3 AND "mSyrupLineManualDrainSR" AND NOT "gIN_HVP301_Aux";
|
||||||
|
|
||||||
|
// Network 17: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF NOT "Procedure_Variables"."FTP302Line_Preparation"."Latch" THEN
|
||||||
|
"Blender_Variables_Pers"."gSyrLinePrepCountInit" := "Profibus_Variables"."gFTP302_Tot";
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 18: BRIX PRODUCT STARTUP THRESHOLD (Original Language: LAD)
|
||||||
|
|
||||||
|
"mSyrBrixAux" := "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupBrix" * "HMI_Blender_Parameters"."ProcessSetup"."_PercSyrupBrixSyrStarUp";
|
||||||
|
|
||||||
|
"mSyrBrixAux_1" := "mSyrBrixAux" / 100.0;
|
||||||
|
|
||||||
|
"Blender_Constants"."gSugaredSyrupBrixThrsd" := "mSyrBrixAux_1";
|
||||||
|
|
||||||
|
// Network 19: Fuzzy Net (Original Language: LAD)
|
||||||
|
|
||||||
|
SEL_R(G := "M_validat_27_01_25" AND "gPV_SyrDensOk" AND "HMI_Device"."PPP302"."Out" AND NOT "Blender_Variables_Pers"."gSugarBeverage", IN0 := 0.0, IN1 := 101.0);
|
||||||
|
|
||||||
|
IF "Blender_Variables_Pers"."gSugarBeverage" THEN
|
||||||
|
"mAux1" := "Profibus_Variables"."gFTP302_Brix" * "HMI_Blender_Parameters"."Actual_Recipe_Parameters"."_SyrupFactor";
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
SEL_R(G := "gIN_SyrTank_MinLvl" AND ("mAux1" > "Blender_Constants"."gSugaredSyrupBrixThrsd"), IN0 := 0.0, IN1 := 101.0);
|
||||||
|
|
||||||
|
IF NOT "M_validat_27_01_25" AND NOT "Blender_Variables_Pers"."gSugarBeverage" THEN
|
||||||
|
"Aux_Somma_Lt" := "HMI_Blender_Parameters"."ProcessSetup"."_SyrupRunOutLiters" + %DBD784;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF NOT "M_validat_27_01_25" AND NOT "Blender_Variables_Pers"."gSugarBeverage" THEN
|
||||||
|
"HMI_Variables_Status"."Analog_Values"."TP301SyrupPrimingCount" := "Profibus_Variables"."gFTP302_Tot" - "Blender_Variables_Pers"."gSyrLinePrepCountInit";
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
"mWaterCountAcheaved" := NOT "mSyrupLineManualDrainSR" AND ("HMI_Variables_Status"."Analog_Values"."TP301SyrupPrimingCount" >= "Aux_Somma_Lt");
|
||||||
|
|
||||||
|
SEL_R(G := "HMI_Device"."PPP302"."Out" AND NOT "mSyrupLineManualDrainSR" AND ("HMI_Variables_Status"."Analog_Values"."TP301SyrupPrimingCount" >= "Aux_Somma_Lt"), IN0 := 0.0, IN1 := 101.0);
|
||||||
|
|
||||||
|
"mDummy" := TRUE;
|
||||||
|
|
||||||
|
// Network 20: Fuzzy Net (Original Language: LAD)
|
||||||
|
|
||||||
|
"mFuzzyNetAdd1" := "mFuzzyNetAdd1" + "mFuzzyNetAdd2";
|
||||||
|
|
||||||
|
"mFuzzyNetAdd1" := "mFuzzyNetAdd1" + "mFuzzyNetAdd3";
|
||||||
|
|
||||||
|
"mFuzzyNetOut" := "Procedure_Variables"."FTP302Line_Preparation"."Latch" AND ("mFuzzyNetAdd1" > 100.0);
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."FTP302Line_Preparation"."Latch" AND NOT "AUX MASTER VALIDATION" AND ("mFuzzyNetAdd1" > 100.0) THEN
|
||||||
|
"Procedure_Variables"."FTP302Line_Preparation"."LinePrepared" := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 21: Opeartor Run Syrup Prep (Original Language: LAD)
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Message__8_ := "gBlenderProdMode" AND "Procedure_Variables"."FTP302Line_Preparation"."Qualifier" AND NOT "Procedure_Variables"."FTP302Line_Preparation"."Latch" AND NOT "Blender_Variables_Pers"."gWaterRecipe" AND NOT "gBlenderRinseMode" AND NOT "Procedure_Variables"."FTP302_StartUp"."Latch" AND NOT "Procedure_Variables"."FTP302Line_Preparation"."Done" AND NOT "System_RunOut_Variables"."FastChangeOverActivated";
|
||||||
|
|
||||||
|
// Network 22: Syrup Tank Prep Running (Original Language: LAD)
|
||||||
|
// Syrup Tank Prep Running Message
|
||||||
|
|
||||||
|
"HMI_Variables_Status"."Procedures"."TP301PrepRun" := "Procedure_Variables"."FTP302Line_Preparation"."Latch";
|
||||||
|
|
||||||
|
// Network 23: Syrup Tank Prep Running (Original Language: LAD)
|
||||||
|
// Syrup Tank Prep Running Message
|
||||||
|
|
||||||
|
_HMI_Alarms___gH_Status__3_ := "Procedure_Variables"."FTP302Line_Preparation"."Latch" OR "Procedure_Variables"."FTP302_StartUp"."Latch";
|
||||||
|
|
||||||
|
// Network 24: (Original Language: LAD)
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."FTP302Line_Preparation"."Running" THEN
|
||||||
|
Syrup_Line_MFM_Prep_Seq(FuzzyNetOut := "mFuzzyNetOut", SyrupLineManualDrained := "mSyrupLineManualDrained", WaterCountAcheaved := "mWaterCountAcheaved", mStep := "mStepNum", mStopPumpP2 := "mStopPumpP2", mSyrMinLevel := "mDelayON_SyrupMinON", mTimer := "mTimeStep", mTransition := "mTransition");
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 25: (Original Language: LAD)
|
||||||
|
|
||||||
|
"HMI_Variables_Status"."System_Run_Out"."TP301PrepDone" := "Procedure_Variables"."FTP302Line_Preparation"."Done";
|
||||||
|
|
||||||
|
END_FUNCTION_BLOCK
|
|
@ -651,9 +651,7 @@ def convert_xml_to_json(xml_filepath, json_filepath):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Fallback si relpath falla con diferentes unidades
|
# Fallback si relpath falla con diferentes unidades
|
||||||
rel_path = json_filepath
|
rel_path = json_filepath
|
||||||
print(
|
print(f"Conversión finalizada. JSON guardado en: '{rel_path}'")
|
||||||
f"Conversión finalizada. JSON guardado en: '{rel_path}'"
|
|
||||||
)
|
|
||||||
return True # Indicar éxito
|
return True # Indicar éxito
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
print(
|
print(
|
||||||
|
|
|
@ -312,9 +312,12 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
# --- NUEVO: Manejar UIDs duplicados antes del procesamiento principal ---
|
# --- NUEVO: Manejar UIDs duplicados antes del procesamiento principal ---
|
||||||
try:
|
try:
|
||||||
from processors.duplicate_uid_handler import detect_and_resolve_duplicate_uids
|
from processors.duplicate_uid_handler import detect_and_resolve_duplicate_uids
|
||||||
|
|
||||||
duplicates_resolved = detect_and_resolve_duplicate_uids(data)
|
duplicates_resolved = detect_and_resolve_duplicate_uids(data)
|
||||||
if duplicates_resolved:
|
if duplicates_resolved:
|
||||||
print("INFO: UIDs duplicados resueltos. Continuando con el procesamiento...")
|
print(
|
||||||
|
"INFO: UIDs duplicados resueltos. Continuando con el procesamiento..."
|
||||||
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print("WARNING: No se pudo cargar el manejador de UIDs duplicados")
|
print("WARNING: No se pudo cargar el manejador de UIDs duplicados")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -4,6 +4,7 @@ LadderToSCL - Conversor de Siemens LAD/FUP XML a SCL
|
||||||
Este script es parte de un conjunto de herramientas para convertir proyectos de Siemens LAD/FUP a SCL.
|
Este script es parte de un conjunto de herramientas para convertir proyectos de Siemens LAD/FUP a SCL.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ToUpload/x3_generate_scl.py
|
# ToUpload/x3_generate_scl.py
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
|
@ -12,6 +13,7 @@ import re
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
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__)))
|
||||||
)
|
)
|
||||||
|
@ -131,9 +133,7 @@ def generate_scl_or_markdown(
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Fallback si relpath falla con diferentes unidades
|
# Fallback si relpath falla con diferentes unidades
|
||||||
rel_path = output_filepath
|
rel_path = output_filepath
|
||||||
print(
|
print(f" -> Escribiendo archivo de salida final en: {rel_path}")
|
||||||
f" -> Escribiendo archivo de salida final en: {rel_path}"
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
# Asegurar que el directorio de salida exista (ya debería estar hecho en __main__)
|
# Asegurar que el directorio de salida exista (ya debería estar hecho en __main__)
|
||||||
os.makedirs(os.path.dirname(output_filepath), exist_ok=True)
|
os.makedirs(os.path.dirname(output_filepath), exist_ok=True)
|
||||||
|
@ -158,7 +158,10 @@ if __name__ == "__main__":
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import filedialog
|
from tkinter import filedialog
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print("Error: Tkinter no está instalado. No se puede mostrar el diálogo de archivo.", file=sys.stderr)
|
print(
|
||||||
|
"Error: Tkinter no está instalado. No se puede mostrar el diálogo de archivo.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
tk = None
|
tk = None
|
||||||
|
|
||||||
input_json_file = ""
|
input_json_file = ""
|
||||||
|
@ -167,14 +170,22 @@ if __name__ == "__main__":
|
||||||
if tk:
|
if tk:
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.withdraw()
|
root.withdraw()
|
||||||
print("Por favor, selecciona el archivo JSON procesado de entrada (generado por x2)...")
|
print(
|
||||||
|
"Por favor, selecciona el archivo JSON procesado de entrada (generado por x2)..."
|
||||||
|
)
|
||||||
input_json_file = filedialog.askopenfilename(
|
input_json_file = filedialog.askopenfilename(
|
||||||
title="Selecciona el archivo JSON procesado de entrada (_processed.json)",
|
title="Selecciona el archivo JSON procesado de entrada (_processed.json)",
|
||||||
filetypes=[("Processed JSON files", "*_processed.json"), ("JSON files", "*.json"), ("All files", "*.*")]
|
filetypes=[
|
||||||
|
("Processed JSON files", "*_processed.json"),
|
||||||
|
("JSON files", "*.json"),
|
||||||
|
("All files", "*.*"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
if input_json_file:
|
if input_json_file:
|
||||||
print(f"Archivo JSON procesado seleccionado: {input_json_file}")
|
print(f"Archivo JSON procesado seleccionado: {input_json_file}")
|
||||||
print("Por favor, selecciona el directorio raíz del proyecto XML (ej. la carpeta 'PLC')...")
|
print(
|
||||||
|
"Por favor, selecciona el directorio raíz del proyecto XML (ej. la carpeta 'PLC')..."
|
||||||
|
)
|
||||||
project_root_dir = filedialog.askdirectory(
|
project_root_dir = filedialog.askdirectory(
|
||||||
title="Selecciona el directorio raíz del proyecto XML"
|
title="Selecciona el directorio raíz del proyecto XML"
|
||||||
)
|
)
|
||||||
|
@ -191,14 +202,24 @@ if __name__ == "__main__":
|
||||||
# <-- NUEVO: Leer nombre del directorio de salida desde la configuración -->
|
# <-- NUEVO: Leer nombre del directorio de salida desde la configuración -->
|
||||||
configs = load_configuration()
|
configs = load_configuration()
|
||||||
xml_parser_config = configs.get("XML Parser to SCL", {})
|
xml_parser_config = configs.get("XML Parser to SCL", {})
|
||||||
cfg_scl_output_dirname = xml_parser_config.get("scl_output_dir", "scl_output") # Leer con default
|
cfg_scl_output_dirname = xml_parser_config.get(
|
||||||
|
"scl_output_dir", "scl_output"
|
||||||
|
) # Leer con default
|
||||||
# <-- FIN NUEVO -->
|
# <-- FIN NUEVO -->
|
||||||
|
|
||||||
final_output_dir = os.path.join(project_root_dir, cfg_scl_output_dirname) # Usar valor leído
|
final_output_dir = os.path.join(
|
||||||
|
project_root_dir, cfg_scl_output_dirname
|
||||||
|
) # Usar valor leído
|
||||||
|
|
||||||
print(f"(x3 - Standalone) Generando SCL/MD desde: '{os.path.relpath(input_json_file)}'")
|
print(
|
||||||
print(f"(x3 - Standalone) Directorio de salida final: '{os.path.relpath(final_output_dir)}'")
|
f"(x3 - Standalone) Generando SCL/MD desde: '{os.path.relpath(input_json_file)}'"
|
||||||
print(f"(x3 - Standalone) Usando ruta raíz del proyecto: '{project_root_dir}' para buscar UDTs.")
|
)
|
||||||
|
print(
|
||||||
|
f"(x3 - Standalone) Directorio de salida final: '{os.path.relpath(final_output_dir)}'"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"(x3 - Standalone) Usando ruta raíz del proyecto: '{project_root_dir}' para buscar UDTs."
|
||||||
|
)
|
||||||
|
|
||||||
# Asegurar que el directorio de salida final exista
|
# Asegurar que el directorio de salida final exista
|
||||||
try:
|
try:
|
||||||
|
@ -223,7 +244,10 @@ if __name__ == "__main__":
|
||||||
print("\nGeneración de SCL/MD completada exitosamente.")
|
print("\nGeneración de SCL/MD completada exitosamente.")
|
||||||
else:
|
else:
|
||||||
# La función generate_scl_or_markdown ya imprime el error
|
# La función generate_scl_or_markdown ya imprime el error
|
||||||
print(f"\nError durante la generación desde '{os.path.relpath(input_json_file)}'.", file=sys.stderr)
|
print(
|
||||||
|
f"\nError durante la generación desde '{os.path.relpath(input_json_file)}'.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
# sys.exit(1) # No usar sys.exit
|
# sys.exit(1) # No usar sys.exit
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error Crítico no manejado en x3: {e}", file=sys.stderr)
|
print(f"Error Crítico no manejado en x3: {e}", file=sys.stderr)
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
{
|
{
|
||||||
"history": [
|
"history": [
|
||||||
|
{
|
||||||
|
"id": "66baa92e",
|
||||||
|
"group_id": "2",
|
||||||
|
"script_name": "main.py",
|
||||||
|
"executed_date": "2025-08-28T09:54:46.647326Z",
|
||||||
|
"arguments": [],
|
||||||
|
"working_directory": "D:/Proyectos/Scripts/RS485/MaselliSimulatorApp",
|
||||||
|
"python_env": "tia_scripting",
|
||||||
|
"executable_type": "pythonw.exe",
|
||||||
|
"status": "running",
|
||||||
|
"pid": 29432,
|
||||||
|
"execution_time": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "4372845c",
|
"id": "4372845c",
|
||||||
"group_id": "2",
|
"group_id": "2",
|
||||||
|
|
52145
data/log.txt
52145
data/log.txt
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue