SOmewhat working

This commit is contained in:
ilia gu 2025-08-18 13:20:34 +04:00
parent e06a57dbc2
commit d8516dd302
167 changed files with 12062 additions and 18789 deletions

View File

@ -76,15 +76,20 @@ class ControllerBuilder:
attach extra modules before the project is saved.
"""
def __init__(self, controller_name: str, skip_chassis_modules: bool = False):
def __init__(self, controller_name: str, skip_chassis_modules: bool = False, boilerplate_dir: str = "boilerplate"):
self.controller_name = controller_name
self.skip_chassis_modules = skip_chassis_modules
self.boilerplate_dir = boilerplate_dir
# Raw base XML snippets to preserve CDATA on save
self._raw_base_aoi_xml: Optional[str] = None
self._raw_base_dtypes_xml: Optional[str] = None
# 1. Build base controller from boilerplate
controller_cfg = create_l83es_controller(controller_name)
# Update boilerplate path to use project-specific directory
if hasattr(controller_cfg, 'boilerplate_path'):
filename = os.path.basename(controller_cfg.boilerplate_path)
controller_cfg.boilerplate_path = os.path.join(self.boilerplate_dir, filename)
gen = L83ESControllerGenerator(controller_cfg)
gen.load_boilerplate()
gen.apply_updates()
@ -112,6 +117,17 @@ class ControllerBuilder:
raise ValueError("<Modules> section missing builder initialisation failed")
return modules
def _set_generator_boilerplate_dir(self, generator):
"""Set the boilerplate directory for a generator if it supports it."""
if hasattr(generator, 'boilerplate_path') and hasattr(generator, 'boilerplate_filename'):
# Update the boilerplate path to use the project-specific directory
generator.boilerplate_path = os.path.join(self.boilerplate_dir, generator.boilerplate_filename)
elif hasattr(generator, 'config') and hasattr(generator.config, 'boilerplate_path'):
# For generators that store boilerplate_path in config
filename = os.path.basename(generator.config.boilerplate_path)
generator.config.boilerplate_path = os.path.join(self.boilerplate_dir, filename)
return generator
def finalise_and_save(self, filename: str):
"""Complete remaining sections and write the finished L5X file."""
# Add logical program/task scaffolding only once at the end so that any
@ -451,7 +467,7 @@ class ControllerBuilder:
def _add_en4tr_module(self, modules_section: ET.Element):
cfg = create_en4tr_module("SLOT2_EN4TR", self.controller_name)
gen = EN4TRModuleGenerator(cfg)
gen = self._set_generator_boilerplate_dir(EN4TRModuleGenerator(cfg))
gen.load_boilerplate()
gen.apply_updates()
@ -466,7 +482,7 @@ class ControllerBuilder:
def _add_ib16_module(self, modules_section: ET.Element):
cfg = create_ib16_module("SLOT5_IB16", "5", "Local", "1", None)
gen = IB16ModuleGenerator(cfg)
gen = self._set_generator_boilerplate_dir(IB16ModuleGenerator(cfg))
gen.load_boilerplate()
gen.apply_updates()
@ -481,7 +497,7 @@ class ControllerBuilder:
def _add_ob16e_module(self, modules_section: ET.Element):
cfg = create_ob16e_module("SLOT6_OB16E", "6", "Local", "1", None)
gen = OB16EModuleGenerator(cfg)
gen = self._set_generator_boilerplate_dir(OB16EModuleGenerator(cfg))
gen.load_boilerplate()
gen.apply_updates()
@ -504,7 +520,7 @@ class ControllerBuilder:
"16#0000_4c33_031d_8f1b",
None,
)
gen = IB16SModuleGenerator(cfg)
gen = self._set_generator_boilerplate_dir(IB16SModuleGenerator(cfg))
gen.load_boilerplate()
gen.apply_updates()

View File

@ -38,14 +38,18 @@ from models.sio_boilerplate_model import create_sio_module, SIOModuleGenerator
class EnhancedMCMGenerator:
"""Enhanced MCM generator that processes Excel data and generates complete L5X projects."""
def __init__(self, project_name: str, excel_file: str = "MCM04_Data.xlsx", zones_dict=None):
def __init__(self, project_name: str, excel_file: str = "MCM04_Data.xlsx", zones_dict=None, boilerplate_dir: str = "boilerplate"):
self.project_name = project_name
self.controller_name = project_name
self.excel_file = excel_file
self.zones_dict = zones_dict
self.boilerplate_dir = boilerplate_dir
self.generated_dir = "generated_projects"
os.makedirs(self.generated_dir, exist_ok=True)
# Set global boilerplate directory for all models to use
os.environ['MCM_BOILERPLATE_DIR'] = boilerplate_dir
# Initialize data processor
self.data_processor = ExcelDataProcessor(excel_file)
@ -67,6 +71,53 @@ class EnhancedMCMGenerator:
self.ib16s_modules = []
self.ob16e_modules = []
def _set_generator_boilerplate_dir(self, generator):
"""Set the boilerplate directory for a generator if it supports it."""
if hasattr(generator, 'boilerplate_path') and hasattr(generator, 'boilerplate_filename'):
# Update the boilerplate path to use the project-specific directory
old_path = generator.boilerplate_path
generator.boilerplate_path = os.path.join(self.boilerplate_dir, generator.boilerplate_filename)
# Force reset and reload with the new path
if hasattr(generator, 'tree'):
generator.tree = None
if hasattr(generator, 'root'):
generator.root = None
try:
generator.load_boilerplate()
print(f" Successfully loaded boilerplate: {generator.boilerplate_path}")
except FileNotFoundError:
# If project-specific boilerplate doesn't exist, fall back to default
print(f" Warning: Project-specific boilerplate not found, using default for {generator.boilerplate_filename}")
generator.boilerplate_path = old_path
if hasattr(generator, 'tree'):
generator.tree = None
if hasattr(generator, 'root'):
generator.root = None
generator.load_boilerplate()
elif hasattr(generator, 'config') and hasattr(generator.config, 'boilerplate_path'):
# For generators that store boilerplate_path in config
filename = os.path.basename(generator.config.boilerplate_path)
old_path = generator.config.boilerplate_path
generator.config.boilerplate_path = os.path.join(self.boilerplate_dir, filename)
# Force reset and reload with the new path
if hasattr(generator, 'tree'):
generator.tree = None
if hasattr(generator, 'root'):
generator.root = None
try:
generator.load_boilerplate()
print(f" Successfully loaded boilerplate: {generator.config.boilerplate_path}")
except FileNotFoundError:
# If project-specific boilerplate doesn't exist, fall back to default
print(f" Warning: Project-specific boilerplate not found, using default for {filename}")
generator.config.boilerplate_path = old_path
if hasattr(generator, 'tree'):
generator.tree = None
if hasattr(generator, 'root'):
generator.root = None
generator.load_boilerplate()
return generator
def _optimize_for_large_projects(self):
"""Apply optimizations for large projects to reduce SDK compilation burden."""
total_modules = sum([
@ -383,7 +434,7 @@ class EnhancedMCMGenerator:
from controller_builder import ControllerBuilder
# 1. Initialise builder (creates base controller + fixed chassis modules)
builder = ControllerBuilder(self.controller_name, skip_chassis_modules=True)
builder = ControllerBuilder(self.controller_name, skip_chassis_modules=True, boilerplate_dir=self.boilerplate_dir)
# 2. Append all Excel-derived modules into the builder's <Modules> section
modules_section = builder.get_modules_section()
@ -680,7 +731,7 @@ class EnhancedMCMGenerator:
from controller_builder import ControllerBuilder
# Create builder
builder = ControllerBuilder(project_name, skip_chassis_modules=True)
builder = ControllerBuilder(project_name, skip_chassis_modules=True, boilerplate_dir=self.boilerplate_dir)
modules_section = builder.get_modules_section()
# Add modules from the specific groups
@ -707,32 +758,32 @@ class EnhancedMCMGenerator:
"""Add modules from specific groups to the modules section."""
factory_map = {
"iolm_modules": lambda entry: M12DRModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"iolm_modules": lambda entry: self._set_generator_boilerplate_dir(
M12DRModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"zmx_modules": lambda entry: ZMXModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"zmx_modules": lambda entry: self._set_generator_boilerplate_dir(
ZMXModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"extendo_modules": lambda entry: ExtendoModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"extendo_modules": lambda entry: self._set_generator_boilerplate_dir(
ExtendoModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"fioh_modules": lambda entry: TurckHubModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"fioh_modules": lambda entry: self._set_generator_boilerplate_dir(
TurckHubModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"apf_modules": lambda entry: APFModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]], hp=entry["hp"]
"apf_modules": lambda entry: self._set_generator_boilerplate_dir(
APFModuleGenerator.from_excel(self.data_processor.modules[entry["name"]], hp=entry["hp"])
),
"vfd_modules": lambda entry: VFDModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]], hp=entry["hp"]
"vfd_modules": lambda entry: self._set_generator_boilerplate_dir(
VFDModuleGenerator.from_excel(self.data_processor.modules[entry["name"]], hp=entry["hp"])
),
"dpm_modules": lambda entry: DPMModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"dpm_modules": lambda entry: self._set_generator_boilerplate_dir(
DPMModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"pmm_modules": lambda entry: PMMModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"pmm_modules": lambda entry: self._set_generator_boilerplate_dir(
PMMModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"sio_modules": lambda entry: SIOModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"sio_modules": lambda entry: self._set_generator_boilerplate_dir(
SIOModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"beacon_modules": lambda entry: TL70BeaconGenerator.from_mapping(entry),
"lpe_modules": lambda entry: LPEBoilerplateGenerator.from_mapping(entry),
@ -773,6 +824,11 @@ class EnhancedMCMGenerator:
for entry in entries:
try:
gen = factory(entry)
# Ensure boilerplate directory is set for all generators
gen = self._set_generator_boilerplate_dir(gen)
# Re-apply updates after boilerplate directory change
if hasattr(gen, 'apply_updates'):
gen.apply_updates()
module_elem = gen.root.find(
f".//Module[@Name='{entry['name']}']"
)
@ -996,7 +1052,7 @@ class EnhancedMCMGenerator:
def _add_en4tr_module(self, modules_section):
"""Add EN4TR module to the Modules section."""
config = create_en4tr_module("SLOT2_EN4TR", self.controller_name)
generator = EN4TRModuleGenerator(config)
generator = self._set_generator_boilerplate_dir(EN4TRModuleGenerator(config))
generator.load_boilerplate()
generator.apply_updates()
@ -1015,32 +1071,32 @@ class EnhancedMCMGenerator:
# specialised helpers due to their CDATA or dict-based quirks).
factory_map = {
"iolm_modules": lambda entry: M12DRModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"iolm_modules": lambda entry: self._set_generator_boilerplate_dir(
M12DRModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"zmx_modules": lambda entry: ZMXModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"zmx_modules": lambda entry: self._set_generator_boilerplate_dir(
ZMXModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"extendo_modules": lambda entry: ExtendoModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"extendo_modules": lambda entry: self._set_generator_boilerplate_dir(
ExtendoModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"fioh_modules": lambda entry: TurckHubModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"fioh_modules": lambda entry: self._set_generator_boilerplate_dir(
TurckHubModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"apf_modules": lambda entry: APFModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]], hp=entry["hp"]
"apf_modules": lambda entry: self._set_generator_boilerplate_dir(
APFModuleGenerator.from_excel(self.data_processor.modules[entry["name"]], hp=entry["hp"])
),
"vfd_modules": lambda entry: VFDModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]], hp=entry["hp"]
"vfd_modules": lambda entry: self._set_generator_boilerplate_dir(
VFDModuleGenerator.from_excel(self.data_processor.modules[entry["name"]], hp=entry["hp"])
),
"dpm_modules": lambda entry: DPMModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"dpm_modules": lambda entry: self._set_generator_boilerplate_dir(
DPMModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"pmm_modules": lambda entry: PMMModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
),
"sio_modules": lambda entry: SIOModuleGenerator.from_excel(
self.data_processor.modules[entry["name"]]
"sio_modules": lambda entry: self._set_generator_boilerplate_dir(
SIOModuleGenerator.from_excel(self.data_processor.modules[entry["name"]])
),
"beacon_modules": lambda entry: TL70BeaconGenerator.from_mapping(entry),
"lpe_modules": lambda entry: LPEBoilerplateGenerator.from_mapping(entry),
@ -1082,9 +1138,11 @@ class EnhancedMCMGenerator:
for entry in entries:
try:
gen = factory(entry)
# Apply optimizations for large projects
if self._optimize_for_large_projects():
gen = self._apply_module_optimizations(gen)
# Ensure boilerplate directory is set for all generators
gen = self._set_generator_boilerplate_dir(gen)
# Re-apply updates after boilerplate directory change
if hasattr(gen, 'apply_updates'):
gen.apply_updates()
# Apply optimizations for large projects
if self._optimize_for_large_projects():
gen = self._apply_module_optimizations(gen)
@ -1170,21 +1228,25 @@ def main():
print(f"ERROR: Invalid zones JSON: {e}")
return
# Allow specifying Excel file and project name via command line
# Usage: python enhanced_mcm_generator.py <excel_file> <project_name> [--split] [--zones <json>]
# Allow specifying Excel file, project name, and boilerplate directory via command line
# Usage: python enhanced_mcm_generator.py <excel_file> <project_name> [boilerplate_dir] [--split] [--zones <json>]
boilerplate_dir = "boilerplate" # Default
if len(sys.argv) > 1 and not sys.argv[1].startswith("--"):
excel_file = sys.argv[1]
if len(sys.argv) > 2 and not sys.argv[2].startswith("--"):
project_name = sys.argv[2]
if len(sys.argv) > 3 and not sys.argv[3].startswith("--"):
boilerplate_dir = sys.argv[3]
print("Enhanced MCM Generator")
print(f"- Project: {project_name}")
print(f"- Excel: {excel_file}")
print(f"- Boilerplate: {boilerplate_dir}")
print(f"- Mode: {'Split' if split_mode else 'Single file'}")
print("-" * 50)
# Create generator with zones
generator = EnhancedMCMGenerator(project_name, excel_file, zones_dict)
# Create generator with zones and boilerplate directory
generator = EnhancedMCMGenerator(project_name, excel_file, zones_dict, boilerplate_dir)
# Load and process Excel data
if generator.load_and_process_data():

File diff suppressed because one or more lines are too long

View File

@ -60,7 +60,9 @@ class APFModuleGenerator:
raise ValueError(f"Unsupported HP value: {self.config.hp}. Supported values: 1, 2, 3, 5, 7.5 (or 7_5), 10")
self.boilerplate_filename = self.HP_BOILERPLATE_MAP[self.config.hp]
self.boilerplate_path = os.path.join("boilerplate", self.boilerplate_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, self.boilerplate_filename)
self.tree = None
self.root = None

View File

@ -34,7 +34,9 @@ class DPMModuleGenerator:
def __init__(self, config: DPMModuleConfig):
self.config = config
self.boilerplate_path = os.path.join("boilerplate", "DPM_Module.L5X")
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, "DPM_Module.L5X")
self.tree = None
self.root = None

View File

@ -6,6 +6,7 @@ This module provides functionality to generate EN4TR module L5X files by
loading a boilerplate template and modifying specific fields.
"""
import os
from dataclasses import dataclass, field
from typing import Optional
from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
@ -16,7 +17,7 @@ class EN4TRModuleConfig(BaseModuleConfig):
"""Configuration for an EN4TR module."""
name: str
ethernet_address: str # e.g., "11.200.1.1"
boilerplate_path: str = "boilerplate/SLOT2_EN4TR_Module.L5X"
boilerplate_path: str = field(default_factory=lambda: os.path.join(os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate'), 'SLOT2_EN4TR_Module.L5X'))
parent_module: str = "Local"
parent_port_id: str = "1"
slot_address: str = "2"

View File

@ -32,7 +32,9 @@ class ExtendoModuleGenerator:
def __init__(self, config: ExtendoModuleConfig):
self.config = config
self.boilerplate_filename = "EXTENDO_Module.L5X"
self.boilerplate_path = os.path.join("boilerplate", self.boilerplate_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, self.boilerplate_filename)
self.tree = None
self.root = None

View File

@ -31,7 +31,9 @@ class FestoSolenoidGenerator:
def __init__(self, config: FestoSolenoidConfig):
self.config = config
self.boilerplate_path = os.path.join("boilerplate", "Festo_Solenoids_Module.L5X")
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, "Festo_Solenoids_Module.L5X")
self.tree = None
self.root = None

View File

@ -6,7 +6,8 @@ This module provides functionality to generate IB16 module L5X files by
loading a boilerplate template and modifying specific fields.
"""
from dataclasses import dataclass
import os
from dataclasses import dataclass, field
from typing import Optional, Dict
import xml.etree.ElementTree as ET
from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
@ -16,7 +17,7 @@ from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
class IB16ModuleConfig(BaseModuleConfig):
"""Configuration for an IB16 module."""
name: str
boilerplate_path: str = "boilerplate/SLOT5_IB16_Module.L5X"
boilerplate_path: str = field(default_factory=lambda: os.path.join(os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate'), 'SLOT5_IB16_Module.L5X'))
slot_address: str = "5"
parent_module: str = "Local"
parent_port_id: str = "1"

View File

@ -6,7 +6,8 @@ This module provides functionality to generate IB16S safety module L5X files by
loading a boilerplate template and modifying specific fields.
"""
from dataclasses import dataclass
import os
from dataclasses import dataclass, field
from typing import Optional, Dict
import xml.etree.ElementTree as ET
from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
@ -16,7 +17,7 @@ from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
class IB16SModuleConfig(BaseModuleConfig):
"""Configuration for an IB16S safety module."""
name: str
boilerplate_path: str = "boilerplate/SLOT7_IB16S_Module.L5X"
boilerplate_path: str = field(default_factory=lambda: os.path.join(os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate'), 'SLOT7_IB16S_Module.L5X'))
slot_address: str = "7"
parent_module: str = "Local"
parent_port_id: str = "1"

View File

@ -6,7 +6,8 @@ This module provides functionality to generate L83ES controller L5X files by
loading a boilerplate template and modifying specific fields.
"""
from dataclasses import dataclass
import os
from dataclasses import dataclass, field
from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
@ -14,7 +15,7 @@ from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
class L83ESControllerConfig(BaseModuleConfig):
"""Configuration for an L83ES controller."""
name: str
boilerplate_path: str = "boilerplate/SLOT0_L83ES.L5X"
boilerplate_path: str = field(default_factory=lambda: os.path.join(os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate'), 'SLOT0_L83ES.L5X'))
processor_type: str = "1756-L83ES"
major_rev: str = "36"
minor_rev: str = "11"

View File

@ -27,7 +27,9 @@ class LPEBoilerplateGenerator:
self.name = name
self.parent_module = parent_module
self.port_address = port_address
self.boilerplate_path = os.path.join("boilerplate", "LPE_Module.L5X")
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, "LPE_Module.L5X")
self.tree = None
self.root = None

View File

@ -49,7 +49,9 @@ class M12DRModuleGenerator:
# Determine the correct boilerplate file
self.boilerplate_filename = self._determine_boilerplate_filename()
self.boilerplate_path = os.path.join("boilerplate", self.boilerplate_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, self.boilerplate_filename)
self.tree = None
self.root = None
@ -65,7 +67,9 @@ class M12DRModuleGenerator:
"""
# First, try module-specific boilerplate
module_specific_filename = f"{self.config.name}_Module.L5X"
module_specific_path = os.path.join("boilerplate", module_specific_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
module_specific_path = os.path.join(boilerplate_dir, module_specific_filename)
if os.path.exists(module_specific_path):
print(f" {self.config.name} (FIO {self.config.variant}): Using module-specific boilerplate {module_specific_filename}")

View File

@ -6,7 +6,8 @@ This module provides functionality to generate OB16E module L5X files by
loading a boilerplate template and modifying specific fields.
"""
from dataclasses import dataclass
import os
from dataclasses import dataclass, field
from typing import Optional, Dict
import xml.etree.ElementTree as ET
from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
@ -16,7 +17,7 @@ from .base_boilerplate_model import BaseModuleConfig, BaseBoilerplateGenerator
class OB16EModuleConfig(BaseModuleConfig):
"""Configuration for an OB16E module."""
name: str
boilerplate_path: str = "boilerplate/SLOT6_OB16E_Module.L5X"
boilerplate_path: str = field(default_factory=lambda: os.path.join(os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate'), 'SLOT6_OB16E_Module.L5X'))
slot_address: str = "6"
parent_module: str = "Local"
parent_port_id: str = "1"

View File

@ -32,7 +32,9 @@ class PMMModuleGenerator:
def __init__(self, config: PMMModuleConfig):
self.config = config
self.boilerplate_filename = "PMM_Module.L5X"
self.boilerplate_path = os.path.join("boilerplate", self.boilerplate_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, self.boilerplate_filename)
self.tree = None
self.root = None

View File

@ -39,7 +39,9 @@ class SIOModuleGenerator:
def __init__(self, config: SIOModuleConfig):
self.config = config
self.boilerplate_path = os.path.join("boilerplate", "SIO_Module.L5X")
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, "SIO_Module.L5X")
self.tree = None
self.root = None

View File

@ -44,7 +44,9 @@ class TL70BeaconGenerator:
def __init__(self, config: TL70BeaconConfig):
self.config = config
self.boilerplate_path = os.path.join("boilerplate", "TL70_Module.L5X")
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, "TL70_Module.L5X")
self.tree = None
self.root = None

View File

@ -82,7 +82,9 @@ class TurckHubModuleGenerator:
# Determine the correct boilerplate file
self.boilerplate_filename = self._determine_boilerplate_filename()
self.boilerplate_path = os.path.join("boilerplate", self.boilerplate_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, self.boilerplate_filename)
# Set default port address if not specified
if not self.config.port_address:
@ -107,7 +109,9 @@ class TurckHubModuleGenerator:
# Second, try module-specific boilerplate
module_specific_filename = f"{self.config.name}_Module.L5X"
module_specific_path = os.path.join("boilerplate", module_specific_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
module_specific_path = os.path.join(boilerplate_dir, module_specific_filename)
if os.path.exists(module_specific_path):
print(f" {self.config.name} (FIOH {self.config.variant}): Using module-specific boilerplate {module_specific_filename}")

View File

@ -45,7 +45,9 @@ class VFDModuleGenerator:
raise ValueError(f"Unsupported HP value: {self.config.hp}. Supported values: 15, 20, 30")
self.boilerplate_filename = self.HP_BOILERPLATE_MAP[self.config.hp]
self.boilerplate_path = os.path.join("boilerplate", self.boilerplate_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, self.boilerplate_filename)
self.tree = None
self.root = None

View File

@ -32,7 +32,9 @@ class ZMXModuleGenerator:
def __init__(self, config: ZMXModuleConfig):
self.config = config
self.boilerplate_filename = "ZMX_Module.L5X"
self.boilerplate_path = os.path.join("boilerplate", self.boilerplate_filename)
# Use project-specific boilerplate directory if set, otherwise default
boilerplate_dir = os.environ.get('MCM_BOILERPLATE_DIR', 'boilerplate')
self.boilerplate_path = os.path.join(boilerplate_dir, self.boilerplate_filename)
self.tree = None
self.root = None

View File

@ -1,75 +0,0 @@
import sys
import pathlib
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent))
import os
import xml.etree.ElementTree as ET
import pytest
from enhanced_mcm_generator import EnhancedMCMGenerator
def _canonicalize_xml(path: str) -> bytes:
"""Return a canonicalised representation of an L5X / XML file.
The function removes volatile attributes (e.g. ExportDate) and sorts
attributes of every element so the resulting byte string is stable
across Python runs and operating systems.
"""
tree = ET.parse(path)
root = tree.getroot()
# Remove volatile attributes that change on every export (present on many elements)
for elem in root.iter():
elem.attrib.pop("ExportDate", None)
# Recursively sort attributes to obtain a deterministic ordering
def _sort_attrs(elem: ET.Element):
if elem.attrib:
# Convert to list with sorted items to keep ElementTree stable
sorted_items = sorted(elem.attrib.items())
elem.attrib.clear()
elem.attrib.update(sorted_items)
for child in elem:
_sort_attrs(child)
_sort_attrs(root)
# Normalise text nodes: strip leading/trailing whitespace so that
# cosmetic indentation inside <Comment> elements does not cause false
# differences.
for elem in root.iter():
if elem.text is not None:
elem.text = elem.text.strip()
# ElementTree does not guarantee attribute ordering when converting to
# string, but because we have manually re-inserted sorted attributes we
# get a deterministic output here.
return ET.tostring(root, encoding="utf-8")
@pytest.mark.regression
def test_generated_project_matches_golden(tmp_path):
"""Generate the project and compare it against the golden reference.
If this test fails, a refactor has changed the *semantic* XML output.
Check the diff to decide whether the change is intended or not.
"""
project_name = "MCM04_Chute_Load"
# 1. Run the generator to build a fresh project under the temporary dir
generator = EnhancedMCMGenerator(project_name, excel_file="Data.xlsx")
assert generator.load_and_process_data(), "Failed to load/process Excel data"
output_path = generator.generate_complete_project()
# 2. Compare with the golden file
golden_path = os.path.join(
"generated_projects", "MCM04_Chute_Load_To_Compare_Against.L5X"
)
assert os.path.exists(golden_path), "Golden file is missing"
assert _canonicalize_xml(output_path) == _canonicalize_xml(
golden_path
), "Generated project differs from golden reference"

View File

@ -1,21 +0,0 @@
import xml.etree.ElementTree as ET
import difflib
import sys
import pathlib
def canon(path):
tree = ET.parse(path)
root = tree.getroot()
for elem in root.iter():
elem.attrib.pop('ExportDate', None)
# sort attributes
if elem.attrib:
items = sorted(elem.attrib.items())
elem.attrib.clear()
elem.attrib.update(items)
return ET.tostring(root, encoding='unicode').splitlines()
a = canon(sys.argv[1])
b = canon(sys.argv[2])
for l in difflib.unified_diff(a,b, lineterm=''):
print(l)

View File

@ -1,6 +1,6 @@
@echo off
echo ====================================
echo PLC Compilation: mtn6
echo PLC Compilation: MTN6_MCM02
echo Project Type: UNKNOWN
echo ====================================
echo.
@ -9,8 +9,8 @@ cd /d "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler"
echo Working directory: %CD%
echo.
if not exist "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.L5X" (
echo ERROR: L5X file not found: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.L5X
if not exist "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.L5X" (
echo ERROR: L5X file not found: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.L5X
pause
exit /b 1
)
@ -61,28 +61,28 @@ if errorlevel 1 (
echo ✓ Logix Designer SDK found
echo.
echo Input L5X file: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.L5X
for %%F in ("C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.L5X") do echo File size: %%~zF bytes
echo Input L5X file: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.L5X
for %%F in ("C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.L5X") do echo File size: %%~zF bytes
echo.
echo Starting compilation...
echo Command: py -3.12 l5x_to_acd.py "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.L5X"
echo Command: py -3.12 l5x_to_acd.py "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.L5X"
echo.
py -3.12 l5x_to_acd.py "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.L5X"
py -3.12 l5x_to_acd.py "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.L5X"
if exist "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.ACD" (
if exist "C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.ACD" (
echo.
echo ====================================
echo SUCCESS: Compilation completed!
echo Output: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.ACD
for %%F in ("C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.ACD") do echo ACD size: %%~zF bytes
echo Output: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.ACD
for %%F in ("C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.ACD") do echo ACD size: %%~zF bytes
echo ====================================
) else (
echo.
echo ====================================
echo ERROR: Compilation failed!
echo Expected output: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\mtn6.ACD
echo Expected output: C:\Users\ilia.gurielidze\Projects\PLC Generation\L5X2ACD Compiler\MTN6_MCM02.ACD
echo ====================================
)

View File

@ -2,6 +2,7 @@
"files": {
"excel_file": "DESC_IP_MERGED.xlsx",
"output_dir": ".",
"zones_file": "zones.json",
"safety_l5x": "SafetyProgram_Generated.L5X",
"main_l5x": "MainProgram_Generated.L5X",
"mapping_txt": "SafetyTagMapping.txt"
@ -10,7 +11,7 @@
"global": {},
"per_routine": {}
},
"routines": [
"routine_plan": [
{
"name": "main_routine",
"plugin": "main_routine",
@ -19,14 +20,6 @@
"order": 10,
"params": {}
},
{
"name": "safety_tag_map",
"plugin": "safety_tag_map",
"enabled": true,
"program": "MainProgram",
"order": 130,
"params": {}
},
{
"name": "mcm",
"plugin": "mcm",
@ -43,18 +36,10 @@
"order": 25,
"params": {}
},
{
"name": "estop_check",
"plugin": "estop_check",
"enabled": true,
"program": "MainProgram",
"order": 120,
"params": {}
},
{
"name": "dpm",
"plugin": "dpm",
"enabled": false,
"enabled": true,
"program": "MainProgram",
"order": 40,
"params": {}
@ -142,7 +127,7 @@
{
"name": "jpe",
"plugin": "jpe",
"enabled": true,
"enabled": false,
"program": "MainProgram",
"order": 150,
"params": {}
@ -210,6 +195,22 @@
"program": "SafetyProgram",
"order": 20,
"params": {}
},
{
"name": "estop_check",
"plugin": "estop_check",
"enabled": true,
"program": "MainProgram",
"order": 120,
"params": {}
},
{
"name": "safety_tag_map",
"plugin": "safety_tag_map",
"enabled": true,
"program": "MainProgram",
"order": 130,
"params": {}
}
],
"xml": {
@ -219,6 +220,47 @@
"target_class": "Standard",
"export_options": "References NoRawData L5KData DecoratedData Context Dependencies ForceProtectedEncoding AllProjDocTrans"
},
"routines": {
"safety_tag_prefix": "SFT_",
"mcm_input_address": "Local:5:I.Data.0",
"mcm_epb_status_inputs": ["Local:7:I.Pt02.Status", "Local:7:I.Pt03.Status"],
"mcm_epb_dcs_inputs": ["Local:7:I.Pt02.Data", "Local:7:I.Pt03.Data"],
"mcm_epb_dcs_tag_name": "MCM_EPB_DCS_CTRL",
"mcm_safety_tag": "MCM_S_PB",
"speed_ctrl_setpoint_tag": "Speed_350_FPM",
"speed_ctrl_setpoint_value": 350,
"no_horn_tag_name": "NO_Horn",
"mcm_base_tag": "MCM",
"mcm_ctrl_tag": "MCM.CTRL",
"rack_fault_tag": "Rack.AOI.Slot2_EN4TR_Faulted",
"mcm_epb_status_tag": "MCM_EPB_STATUS",
"top_level_estop_ok_tag": "EStop_MCM_OK",
"station_ctrl_tag": "Station.CTRL",
"apf_input_default": "In_0",
"mcm_aoi_input_args": [
"Local:5:I.Data.2",
"Local:5:I.Data.5",
"Local:5:I.Data.4",
"Local:5:I.Data.0",
"Local:5:I.Data.3",
"Local:7:I.Pt02.Data",
"Local:7:I.Pt03.Data",
"Local:5:I.Data.1",
"Local:7:I.Pt00.Data",
"Local:5:I.Data.7",
"Local:5:I.Data.8",
"Local:5:I.Data.6",
"Local:5:I.Data.9"
],
"mcm_aoi_output_args": [
"Local:6:O.Data.2",
"Local:6:O.Data.5",
"Local:6:O.Data.4",
"Local:6:O.Data.0",
"Local:6:O.Data.1",
"Local:6:O.Data.3"
]
},
"extraction": {
"rst_desc_contains": [ "START" ],
"rst_desc_excludes": [ "LIGHT" ],

701
MTN6_zones.json Normal file
View File

@ -0,0 +1,701 @@
{
"MCM01": [
{
"name": "MCM01",
"start": "",
"stop": "",
"interlock": ""
},
{
"name": "01-01",
"start": "UL1_1",
"stop": "UL1_13",
"interlock": "MCM01"
},
{
"name": "01-06",
"start": "UL4_1",
"stop": "UL4_13",
"interlock": "MCM01"
},
{
"name": "01-11",
"start": "UL7_1",
"stop": "UL7_13",
"interlock": "MCM01"
},
{
"name": "01-17",
"start": "UL11_1",
"stop": "UL11_13",
"interlock": "MCM01"
},
{
"name": "01-02",
"start": "UL2_1",
"stop": "UL2_10",
"interlock": "01-01"
},
{
"name": "01-03",
"start": "UL3_1",
"stop": "UL3_9",
"interlock": "01-01"
},
{
"name": "01-04",
"start": "PS1_1",
"stop": "PS1_4",
"interlock": "01-01"
},
{
"name": "01-07",
"start": "UL5_1",
"stop": "UL5_10",
"interlock": "01-06"
},
{
"name": "01-08",
"start": "UL6_1",
"stop": "UL6_9",
"interlock": "01-06"
},
{
"name": "01-09",
"start": "PS2_1",
"stop": "PS2_4",
"interlock": "01-06"
},
{
"name": "01-12",
"start": "UL8_1",
"stop": "UL8_9",
"interlock": "01-11"
},
{
"name": "01-13",
"start": "UL9_1",
"stop": "UL9_11",
"interlock": "01-11"
},
{
"name": "01-14",
"start": "PS3_1",
"stop": "PS3_3",
"interlock": "01-11"
},
{
"name": "01-16",
"start": "UL10_1",
"stop": "UL10_10",
"interlock": "01-17"
},
{
"name": "01-18",
"start": "UL12_1",
"stop": "UL12_10",
"interlock": "01-17"
},
{
"name": "01-19",
"start": "PS4_1",
"stop": "PS4_5",
"interlock": "01-17"
},
{
"name": "01-05",
"start": "PS1_5",
"stop": "PS1_5",
"interlock": "MCM01"
},
{
"name": "01-10",
"start": "PS2_5",
"stop": "PS2_6",
"interlock": "MCM01"
},
{
"name": "01-15",
"start": "PS3_8",
"stop": "PS3_12",
"interlock": "MCM01"
},
{
"name": "01-20",
"start": "PS4_11",
"stop": "PS4_14",
"interlock": "MCM01"
},
{
"name": "01-21",
"start": "PS3_4",
"stop": "PS3_7",
"interlock": "MCM01"
}
],
"MCM02": [
{
"name": "MCM02",
"start": "",
"stop": "",
"interlock": ""
},
{
"name": "02-01",
"start": "UL13_1",
"stop": "UL13_12",
"interlock": "MCM02"
},
{
"name": "02-02",
"start": "UL14_1",
"stop": "UL14_10",
"interlock": "02-01"
},
{
"name": "02-03",
"start": "UL15_1",
"stop": "UL15_10",
"interlock": "02-01"
},
{
"name": "02-04",
"start": "PS5_1",
"stop": "PS5_5",
"interlock": "02-01"
},
{
"name": "02-05",
"start": "PS5_12",
"stop": "PS5_13",
"interlock": "MCM02"
},
{
"name": "02-06",
"start": "UL16_1",
"stop": "UL16_9",
"interlock": "02-08"
},
{
"name": "02-07",
"start": "UL17_1",
"stop": "UL17_10",
"interlock": "02-08"
},
{
"name": "02-08",
"start": "UL18_1",
"stop": "UL18_16",
"interlock": "MCM02"
},
{
"name": "02-09",
"start": "PS6_1",
"stop": "PS6_5",
"interlock": "02-08"
},
{
"name": "02-10",
"start": "PS6_12",
"stop": "PS6_13",
"interlock": "MCM02"
},
{
"name": "02-11",
"start": "UL19_1",
"stop": "UL19_9",
"interlock": "02-13"
},
{
"name": "02-12",
"start": "UL20_1",
"stop": "UL20_11",
"interlock": "02-13"
},
{
"name": "02-13",
"start": "UL21_1",
"stop": "UL21_17",
"interlock": "MCM02"
},
{
"name": "02-14",
"start": "PS7_1",
"stop": "PS7_5",
"interlock": "02-13"
},
{
"name": "02-15",
"start": "PS7_8",
"stop": "PS7_9",
"interlock": "MCM02"
},
{
"name": "02-16",
"start": "PS7_11",
"stop": "PS7_14",
"interlock": "MCM02"
}
],
"MCM03": [
{
"name": "MCM03",
"start": "",
"stop": "",
"interlock": ""
},
{
"name": "03-01",
"start": "UL1_14",
"stop": "UL1_20",
"interlock": "03-08"
},
{
"name": "03-02",
"start": "UL4_14",
"stop": "UL4_20",
"interlock": "03-08"
},
{
"name": "03-03",
"start": "UL7_14",
"stop": "UL7_20",
"interlock": "03-08"
},
{
"name": "03-04",
"start": "UL11_14",
"stop": "UL11_20",
"interlock": "03-08"
},
{
"name": "03-05",
"start": "UL13_13",
"stop": "UL13_19",
"interlock": "03-08"
},
{
"name": "03-06",
"start": "UL18_17",
"stop": "UL18_23",
"interlock": "03-08"
},
{
"name": "03-07",
"start": "UL21_18",
"stop": "UL21_24",
"interlock": "03-08"
},
{
"name": "03-08",
"start": "NCP1_1",
"stop": "NCP1_5",
"interlock": "MCM03"
},
{
"name": "03-09",
"start": "NCP1_6",
"stop": "NCP1_8",
"interlock": "MCM03"
}
],"MCM04": [
{
"name": "MCM04",
"start": "",
"stop": "",
"interlock": ""
},
{
"name": "04-01",
"start": "",
"stop": "",
"ranges": [
{"start": "ULC7_1", "stop": "ULC7_3"},
{"start": "ULC8_1", "stop": "ULC8_3"},
{"start": "PS10_1", "stop": "PS10_3"}
],
"interlock": "MCM04"
},
{
"name": "04-02",
"start": "",
"stop": "",
"ranges": [
{"start": "PS10_1", "stop": "PS10_3"},
{"start": "PS11_1", "stop": "PS11_2"}
],
"interlock": "MCM04"
},
{
"name": "04-03",
"start": "PS10_5",
"stop": "PS10_5",
"interlock": "MCM04"
},
{
"name": "04-04",
"start": "",
"stop": "",
"ranges": [
{"start": "ULC5_1", "stop": "ULC5_3"},
{"start": "ULC6_1", "stop": "ULC6_3"},
{"start": "PS11_1", "stop": "PS11_4"}
],
"interlock": "MCM04"
},
{
"name": "04-05",
"start": "PS11_6",
"stop": "PS11_7",
"interlock": "MCM04"
},
{
"name": "04-06",
"start": "PS11_8",
"stop": "PS11_9",
"interlock": "MCM04"
},
{
"name": "04-07",
"start": "PS11_11",
"stop": "PS11_11",
"interlock": "MCM04"
},
{
"name": "04-08",
"start": "PRS3_5",
"stop": "PRS3_6",
"interlock": "MCM04"
},
{
"name": "04-09",
"start": "",
"stop": "",
"ranges": [
{"start": "PRS4_1", "stop": "PRS4_2"},
{"start": "PS11_3", "stop": "PS11_3"}
],
"interlock": "MCM04"
},
{
"name": "FL1014",
"start": "FL1014_2_VFD1",
"stop": "FL1014_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL1018",
"start": "FL1018_2_VFD1",
"stop": "FL1018_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL1022",
"start": "FL1022_2_VFD1",
"stop": "FL1022_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL1026",
"start": "FL1026_2_VFD1",
"stop": "FL1026_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL1034",
"start": "FL1034_2_VFD1",
"stop": "FL1034_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL1038",
"start": "FL1038_2_VFD1",
"stop": "FL1038_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL3012",
"start": "FL3012_2_VFD1",
"stop": "FL3012_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL3016",
"start": "FL3016_2_VFD1",
"stop": "FL3016_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL3020",
"start": "FL3020_2_VFD1",
"stop": "FL3020_4_EX1",
"interlock": "MCM04"
},
{
"name": "FL3024",
"start": "FL3024_2_VFD1",
"stop": "FL3024_4_EX1",
"interlock": "MCM04"
}
],
"MCM05": [
{
"name": "MCM05",
"start": "",
"stop": "",
"interlock": ""
},
{
"name": "05-01",
"start": "",
"stop": "",
"ranges": [
{"start": "ULC1_1", "stop": "ULC1_3"},
{"start": "ULC2_1", "stop": "ULC2_3"},
{"start": "UL3_1", "stop": "UL3_3"},
{"start": "UL4_1", "stop": "UL4_3"},
{"start": "PS8_1", "stop": "PS8_2"},
{"start": "PRS2_1", "stop": "PRS2_1"}
],
"interlock": "MCM05"
},
{
"name": "05-02",
"start": "PS8_4",
"stop": "PS8_5",
"interlock": "MCM05"
},
{
"name": "05-03",
"start": "PS9_2",
"stop": "PS9_3",
"interlock": "MCM05"
},
{
"name": "05-04",
"start": "PS8_11",
"stop": "PS8_11",
"interlock": "MCM05"
},
{
"name": "05-05",
"start": "PRS1_6",
"stop": "PRS1_7",
"interlock": "MCM05"
}
],
"MCM06": [
{
"name": "MCM06",
"start": "",
"stop": "",
"interlock": ""
},
{
"name": "06-01",
"start": "NCP1_9",
"stop": "NCP1_20",
"interlock": "MCM06"
},
{
"name": "06-02",
"start": "NCS1_1",
"stop": "NCS1_9",
"interlock": "MCM06"
},
{
"name": "06-03",
"start": "",
"stop": "",
"ranges": [
{"start": "NCP1_21", "stop": "NCP1_21"},
{"start": "NCS2_1", "stop": "NCS2_7"}
],
"interlock": "MCM06"
},
{
"name": "06-04",
"start": "S02_1",
"stop": "S02_1",
"interlock": "MCM06"
},
{
"name": "06-05",
"start": "S02_2",
"stop": "S02_2",
"interlock": "MCM06"
}
],
"MCM07": [
{
"name": "MCM07",
"start": "",
"stop": "",
"interlock": ""
},
{
"name": "07-01",
"start": "BYAC_2",
"stop": "BYAC_3",
"interlock": "MCM07"
},
{
"name": "07-02",
"start": "BYAD_2",
"stop": "BYAD_3",
"interlock": "MCM07"
},
{
"name": "07-03",
"start": "BYAB_2",
"stop": "BYAB_7",
"interlock": "MCM07"
},
{
"name": "07-04",
"start": "BYAC_8",
"stop": "BYAC_11",
"interlock": "MCM07"
},
{
"name": "07-05",
"start": "BYAD_8",
"stop": "BYAD_9",
"interlock": "MCM07"
},
{
"name": "07-06",
"start": "BYAB_13",
"stop": "BYAB_15",
"interlock": "MCM07"
},
{
"name": "07-07",
"start": "BYBA_2",
"stop": "BYBA_3",
"interlock": "MCM07"
},
{
"name": "07-08",
"start": "BYBC_2",
"stop": "BYBC_3",
"interlock": "MCM07"
},
{
"name": "07-09",
"start": "BYBD_2",
"stop": "BYBD_3",
"interlock": "MCM07"
},
{
"name": "07-10",
"start": "BYBA_10",
"stop": "BYBA_15",
"interlock": "MCM07"
},
{
"name": "07-11",
"start": "BYBC_9",
"stop": "BYBC_10",
"interlock": "MCM07"
},
{
"name": "07-12",
"start": "BYBD_13",
"stop": "BYBD_14",
"interlock": "MCM07"
},
{
"name": "07-13",
"start": "BYCA_2",
"stop": "BYCA_3",
"interlock": "MCM07"
},
{
"name": "07-14",
"start": "BYCB_2",
"stop": "BYCB_3",
"interlock": "MCM07"
},
{
"name": "07-15",
"start": "BYCD_2",
"stop": "BYCD_5",
"interlock": "MCM07"
},
{
"name": "07-16",
"start": "BYCA_6",
"stop": "BYCA_9",
"interlock": "MCM07"
},
{
"name": "07-17",
"start": "BYCB_9",
"stop": "BYCB_10",
"interlock": "MCM07"
},
{
"name": "07-18",
"start": "BYCD_11",
"stop": "BYCD_12",
"interlock": "MCM07"
},
{
"name": "07-19",
"start": "BYDC_2",
"stop": "BYDC_3",
"interlock": "MCM07"
},
{
"name": "07-20",
"start": "BYDA_2",
"stop": "BYDA_3",
"interlock": "MCM07"
},
{
"name": "07-21",
"start": "BYDB_2",
"stop": "BYDB_3",
"interlock": "MCM07"
},
{
"name": "07-22",
"start": "BYDC_9",
"stop": "BYDC_13",
"interlock": "MCM07"
},
{
"name": "07-23",
"start": "BYDA_4",
"stop": "BYDA_9",
"interlock": "MCM07"
},
{
"name": "07-24",
"start": "BYDB_15",
"stop": "BYDB_16",
"interlock": "MCM07"
},
{
"name": "07-25",
"start": "BYDB_4",
"stop": "BYDB_6",
"interlock": "MCM07"
},
{
"name": "07-26",
"start": "BYDC_4",
"stop": "BYDC_8",
"interlock": "MCM07"
}
],
"DEFAULT": [
{
"name": "MCM",
"start": "",
"stop": "",
"interlock": ""
}
]
}

View File

@ -1812,13 +1812,10 @@ UL11_13_FIO1:I.Pt00.Data,UL11_13_PE1 DEBRIS SENSOR,MCM01
UL11_13_FIO1:I.Pt01.Data,SPARE,MCM01
UL11_13_FIO1:I.Pt02.Data,UL11_13_PE2 BELT ENGAGEMENT SENSOR,MCM01
UL11_13_FIO1:I.Pt03.Data,SPARE,MCM01
UL11_13_FIO1:O.Pt05.Data,SPARE,MCM01
UL11_13_FIO1:O.Pt07.Data,SPARE,MCM01
UL11_13_FIO1:I.Pt08.Data,UL11_13_PE3 ENTRANCE PE,MCM01
UL11_13_FIO1:I.Pt09.Data,SPARE,MCM01
UL11_13_FIO1:I.Pt10.Data,UL11_13_PE4 EXIT PE,MCM01
UL11_13_FIO1:I.Pt11.Data,SPARE,MCM01
UL11_13_FIO1:O.Pt13.Data,SPARE,MCM01
UL11_13_FIO1:I.Pt14.Data,UL11_13_PE5 DEBRIS SENSOR,MCM01
UL11_13_FIO1:O.Pt15.Data,SPARE,MCM01
UL11_3_FIO1:O.Pt00.Data,UL11_3_BCN1_R RED BEACON LIGHT,MCM01
@ -1853,13 +1850,10 @@ UL1_13_FIO1:I.Pt00.Data,UL1_13_PE1 DEBRIS SENSOR,MCM01
UL1_13_FIO1:I.Pt01.Data,SPARE,MCM01
UL1_13_FIO1:I.Pt02.Data,UL1_13_PE2 BELT ENGAGEMENT SENSOR,MCM01
UL1_13_FIO1:I.Pt03.Data,SPARE,MCM01
UL1_13_FIO1:O.Pt05.Data,SPARE,MCM01
UL1_13_FIO1:O.Pt07.Data,SPARE,MCM01
UL1_13_FIO1:I.Pt08.Data,UL1_13_PE3 ENTRANCE PE,MCM01
UL1_13_FIO1:I.Pt09.Data,SPARE,MCM01
UL1_13_FIO1:I.Pt10.Data,UL1_13_PE4 EXIT PE,MCM01
UL1_13_FIO1:I.Pt11.Data,SPARE,MCM01
UL1_13_FIO1:O.Pt13.Data,SPARE,MCM01
UL1_13_FIO1:I.Pt14.Data,UL1_13_PE5 DEBRIS SENSOR,MCM01
UL1_13_FIO1:O.Pt15.Data,SPARE,MCM01
UL1_3_FIO1:O.Pt00.Data,UL1_3_BCN1_R RED BEACON LIGHT,MCM01
@ -1908,13 +1902,10 @@ UL4_13_FIO1:I.Pt00.Data,UL4_13_PE1 DEBRIS SENSOR,MCM01
UL4_13_FIO1:I.Pt01.Data,SPARE,MCM01
UL4_13_FIO1:I.Pt02.Data,UL4_13_PE2 BELT ENGAGEMENT SENSOR,MCM01
UL4_13_FIO1:I.Pt03.Data,SPARE,MCM01
UL4_13_FIO1:O.Pt05.Data,SPARE,MCM01
UL4_13_FIO1:O.Pt07.Data,SPARE,MCM01
UL4_13_FIO1:I.Pt08.Data,UL4_13_PE3 ENTRANCE PE,MCM01
UL4_13_FIO1:I.Pt09.Data,SPARE,MCM01
UL4_13_FIO1:I.Pt10.Data,UL4_13_PE4 EXIT PE,MCM01
UL4_13_FIO1:I.Pt11.Data,SPARE,MCM01
UL4_13_FIO1:O.Pt13.Data,SPARE,MCM01
UL4_13_FIO1:I.Pt14.Data,UL4_13_PE5 DEBRIS SENSOR,MCM01
UL4_13_FIO1:O.Pt15.Data,SPARE,MCM01
UL4_3_FIO1:O.Pt00.Data,UL4_3_BCN1_R RED BEACON LIGHT,MCM01
@ -1963,13 +1954,10 @@ UL7_13_FIO1:I.Pt00.Data,UL7_13_PE1 DEBRIS SENSOR,MCM01
UL7_13_FIO1:I.Pt01.Data,SPARE,MCM01
UL7_13_FIO1:I.Pt02.Data,UL7_13_PE2 BELT ENGAGEMENT SENSOR,MCM01
UL7_13_FIO1:I.Pt03.Data,SPARE,MCM01
UL7_13_FIO1:O.Pt05.Data,SPARE,MCM01
UL7_13_FIO1:O.Pt07.Data,SPARE,MCM01
UL7_13_FIO1:I.Pt08.Data,UL7_13_PE3 ENTRANCE PE,MCM01
UL7_13_FIO1:I.Pt09.Data,SPARE,MCM01
UL7_13_FIO1:I.Pt10.Data,UL7_13_PE4 EXIT PE,MCM01
UL7_13_FIO1:I.Pt11.Data,SPARE,MCM01
UL7_13_FIO1:O.Pt13.Data,SPARE,MCM01
UL7_13_FIO1:I.Pt14.Data,UL7_13_PE5 DEBRIS SENSOR,MCM01
UL7_13_FIO1:O.Pt15.Data,SPARE,MCM01
UL7_3_FIO1:O.Pt00.Data,UL7_3_BCN1_R RED BEACON LIGHT,MCM01

1 Name Description Subsystem
1812 UL11_13_FIO1:I.Pt01.Data SPARE MCM01
1813 UL11_13_FIO1:I.Pt02.Data UL11_13_PE2 BELT ENGAGEMENT SENSOR MCM01
1814 UL11_13_FIO1:I.Pt03.Data SPARE MCM01
UL11_13_FIO1:O.Pt05.Data SPARE MCM01
UL11_13_FIO1:O.Pt07.Data SPARE MCM01
1815 UL11_13_FIO1:I.Pt08.Data UL11_13_PE3 ENTRANCE PE MCM01
1816 UL11_13_FIO1:I.Pt09.Data SPARE MCM01
1817 UL11_13_FIO1:I.Pt10.Data UL11_13_PE4 EXIT PE MCM01
1818 UL11_13_FIO1:I.Pt11.Data SPARE MCM01
UL11_13_FIO1:O.Pt13.Data SPARE MCM01
1819 UL11_13_FIO1:I.Pt14.Data UL11_13_PE5 DEBRIS SENSOR MCM01
1820 UL11_13_FIO1:O.Pt15.Data SPARE MCM01
1821 UL11_3_FIO1:O.Pt00.Data UL11_3_BCN1_R RED BEACON LIGHT MCM01
1850 UL1_13_FIO1:I.Pt01.Data SPARE MCM01
1851 UL1_13_FIO1:I.Pt02.Data UL1_13_PE2 BELT ENGAGEMENT SENSOR MCM01
1852 UL1_13_FIO1:I.Pt03.Data SPARE MCM01
UL1_13_FIO1:O.Pt05.Data SPARE MCM01
UL1_13_FIO1:O.Pt07.Data SPARE MCM01
1853 UL1_13_FIO1:I.Pt08.Data UL1_13_PE3 ENTRANCE PE MCM01
1854 UL1_13_FIO1:I.Pt09.Data SPARE MCM01
1855 UL1_13_FIO1:I.Pt10.Data UL1_13_PE4 EXIT PE MCM01
1856 UL1_13_FIO1:I.Pt11.Data SPARE MCM01
UL1_13_FIO1:O.Pt13.Data SPARE MCM01
1857 UL1_13_FIO1:I.Pt14.Data UL1_13_PE5 DEBRIS SENSOR MCM01
1858 UL1_13_FIO1:O.Pt15.Data SPARE MCM01
1859 UL1_3_FIO1:O.Pt00.Data UL1_3_BCN1_R RED BEACON LIGHT MCM01
1902 UL4_13_FIO1:I.Pt01.Data SPARE MCM01
1903 UL4_13_FIO1:I.Pt02.Data UL4_13_PE2 BELT ENGAGEMENT SENSOR MCM01
1904 UL4_13_FIO1:I.Pt03.Data SPARE MCM01
UL4_13_FIO1:O.Pt05.Data SPARE MCM01
UL4_13_FIO1:O.Pt07.Data SPARE MCM01
1905 UL4_13_FIO1:I.Pt08.Data UL4_13_PE3 ENTRANCE PE MCM01
1906 UL4_13_FIO1:I.Pt09.Data SPARE MCM01
1907 UL4_13_FIO1:I.Pt10.Data UL4_13_PE4 EXIT PE MCM01
1908 UL4_13_FIO1:I.Pt11.Data SPARE MCM01
UL4_13_FIO1:O.Pt13.Data SPARE MCM01
1909 UL4_13_FIO1:I.Pt14.Data UL4_13_PE5 DEBRIS SENSOR MCM01
1910 UL4_13_FIO1:O.Pt15.Data SPARE MCM01
1911 UL4_3_FIO1:O.Pt00.Data UL4_3_BCN1_R RED BEACON LIGHT MCM01
1954 UL7_13_FIO1:I.Pt01.Data SPARE MCM01
1955 UL7_13_FIO1:I.Pt02.Data UL7_13_PE2 BELT ENGAGEMENT SENSOR MCM01
1956 UL7_13_FIO1:I.Pt03.Data SPARE MCM01
UL7_13_FIO1:O.Pt05.Data SPARE MCM01
UL7_13_FIO1:O.Pt07.Data SPARE MCM01
1957 UL7_13_FIO1:I.Pt08.Data UL7_13_PE3 ENTRANCE PE MCM01
1958 UL7_13_FIO1:I.Pt09.Data SPARE MCM01
1959 UL7_13_FIO1:I.Pt10.Data UL7_13_PE4 EXIT PE MCM01
1960 UL7_13_FIO1:I.Pt11.Data SPARE MCM01
UL7_13_FIO1:O.Pt13.Data SPARE MCM01
1961 UL7_13_FIO1:I.Pt14.Data UL7_13_PE5 DEBRIS SENSOR MCM01
1962 UL7_13_FIO1:O.Pt15.Data SPARE MCM01
1963 UL7_3_FIO1:O.Pt00.Data UL7_3_BCN1_R RED BEACON LIGHT MCM01

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,189 +0,0 @@
import pandas as pd
import sys
import os
import re
def extract_fio_fioh_modules(input_file='MCM04_DESC_IP_MERGED.xlsx', output_file='FIO_FIOH_OUTPUT.csv'):
"""
Extract FIO and FIOH modules from DESC/IP sheet and create output with format:
TAGNAME, ADDR, TERM, TERMDESC, DESCA, DESCB
"""
try:
# Read the DESC/IP merged data
print(f"Reading input file: {input_file}")
xl = pd.ExcelFile(input_file)
# Try to auto-detect the DESC/IP sheet (kept for backward compatibility)
df = pd.read_excel(xl, sheet_name='DESC_IP')
print(f"Total rows in DESC_IP sheet: {len(df)}")
# --- Load NETWORK sheet for DPM mapping ----------------------------
network_sheet = None
for sheet in xl.sheet_names:
if 'NETWORK' in sheet.upper():
network_sheet = sheet
break
if network_sheet:
network_df = pd.read_excel(xl, sheet_name=network_sheet)
print(f"Loaded NETWORK sheet: {network_sheet} ({len(network_df)} rows)")
# Build mapping from Name -> DPM (blank-safe)
network_df['Name'] = network_df['Name'].astype(str).str.strip()
network_df['DPM'] = network_df['DPM'].fillna('').astype(str).str.strip()
name_to_dpm = dict(zip(network_df['Name'], network_df['DPM']))
else:
print("WARNING: NETWORK sheet not found in workbook DPM column will be blank for masters")
name_to_dpm = {}
except FileNotFoundError:
print(f"ERROR: File {input_file} not found!")
return
except Exception as e:
print(f"ERROR: Failed to read {input_file}: {str(e)}")
return
# ---------------------------------------------------------------------
# Build a mapping of FIOH tag -> its MASTER FIO tag by scanning DESC_IP
# Rows where DESCA contains 'FIOH' typically reference the hub on a master
# channel. We use these to derive the master relationship.
fioh_master_map = {}
fioh_ref_rows = df[df['DESCA'].astype(str).str.contains('FIOH', case=False, na=False)]
for _, r in fioh_ref_rows.iterrows():
fioh_tag = str(r['DESCA']).strip()
master_tag = str(r['TAGNAME']).strip()
# Keep the first master encountered to avoid overriding inconsistencies
fioh_master_map.setdefault(fioh_tag, master_tag)
# Filter for FIO and FIOH modules (TAGNAME containing "FIO")
fio_fioh_filter = df['TAGNAME'].str.contains('FIO', case=False, na=False)
fio_fioh_data = df[fio_fioh_filter].copy()
print(f"Found {len(fio_fioh_data)} FIO/FIOH entries")
if len(fio_fioh_data) == 0:
print("No FIO/FIOH modules found in the data!")
return
# Get unique module names
unique_modules = fio_fioh_data['TAGNAME'].unique()
print(f"Found {len(unique_modules)} unique FIO/FIOH modules")
# Define channel mappings based on device type
def get_channels_for_device(device_type):
"""Return list of channels for a given device type"""
if device_type == 'M12DR': # FIO devices
return [f'IO{i}' for i in range(16)] # IO0 to IO15
elif device_type == 'Hub': # FIOH devices
return [f'IO{i}' for i in range(16)] # IO0 to IO15
else:
return []
# Prepare output data
output_rows = []
for module_name in unique_modules:
# Get module data
module_data = fio_fioh_data[fio_fioh_data['TAGNAME'] == module_name]
if len(module_data) == 0:
continue
# Get device type from first row
device_type = module_data.iloc[0]['DEVICE_TYPE']
channels = get_channels_for_device(device_type)
print(f"Processing {module_name} ({device_type}) - {len(channels)} channels")
# Create a mapping of existing data by TERM
existing_data = {}
for _, row in module_data.iterrows():
term = str(row['TERM']).strip()
existing_data[term] = {
'DESCA': row['DESCA'] if pd.notna(row['DESCA']) else '',
'DESCB': row['DESCB'] if pd.notna(row['DESCB']) else ''
}
# Generate output rows for all channels
for channel in channels:
# Create ADDR by combining module name with channel
addr = f"{module_name}_{channel}"
# Get DESCA and DESCB from existing data if available
if channel in existing_data:
desca = existing_data[channel]['DESCA']
descb = existing_data[channel]['DESCB']
else:
# Default to SPARE if no existing data
desca = 'SPARE'
descb = ''
# Determine DPM value based on device type
if device_type == 'M12DR': # Master FIO
dpm_value = name_to_dpm.get(module_name, '')
elif device_type == 'Hub': # FIOH use its master
dpm_value = fioh_master_map.get(module_name, '')
else:
dpm_value = ''
output_rows.append({
'TAGNAME': module_name,
'ADDR': addr,
'TERM': channel,
'TERMDESC': '', # Empty as shown in example
'DESCA': desca,
'DESCB': descb,
'DPM': dpm_value
})
# Create output DataFrame
output_df = pd.DataFrame(output_rows)
# Extract numeric part from TERM for natural sorting
def extract_io_number(term):
"""Extract the numeric part from IO term for proper sorting"""
match = re.match(r'IO(\d+)', term)
if match:
return int(match.group(1))
return 0
# Add a temporary column for sorting
output_df['TERM_NUM'] = output_df['TERM'].apply(extract_io_number)
# Sort by TAGNAME and then by the numeric value of TERM
output_df = output_df.sort_values(['TAGNAME', 'TERM_NUM'])
# Drop the temporary column
output_df = output_df.drop(columns=['TERM_NUM'])
print(f"\nGenerated {len(output_df)} output rows")
print(f"Saving to: {output_file}")
# Replace any NaN values with empty strings for clean output
output_df = output_df.fillna('')
# Ensure DPM column is last (you can change order if desired)
cols = ['TAGNAME', 'ADDR', 'TERM', 'TERMDESC', 'DESCA', 'DESCB', 'DPM']
output_df = output_df[cols]
# Save to CSV
output_df.to_csv(output_file, index=False)
print(f"\nSample output:")
print(output_df.head(15))
print(f"\nOutput saved successfully to {output_file}")
return output_df
if __name__ == "__main__":
# Check if custom input file is provided
if len(sys.argv) > 1:
input_file = sys.argv[1]
else:
input_file = 'MCM04_DESC_IP_MERGED.xlsx'
# Check if custom output file is provided
if len(sys.argv) > 2:
output_file = sys.argv[2]
else:
output_file = 'FIO_FIOH_OUTPUT.csv'
extract_fio_fioh_modules(input_file, output_file)

View File

@ -1,75 +0,0 @@
import pandas as pd
import re
# Read the Excel file
input_file = 'mcm04 very last.xlsx'
df = pd.read_excel(input_file)
# Prepare output rows
output_rows = []
io_columns = [f'IO{i}' for i in range(16)]
# First pass: collect all prefixes with JR1_PB (JAM RESET PUSHBUTTON)
jam_reset_prefixes = set()
for _, row in df.iterrows():
for io_col in io_columns:
val = row.get(io_col, '')
if pd.isna(val) or val == '':
continue
if 'JR1_PB' in str(val):
m = re.match(r'(S\d+)_', str(val))
if m:
jam_reset_prefixes.add(m.group(1))
# Second pass: build output with DESB logic
def get_prefix(tag):
m = re.match(r'(S\d+)_', str(tag))
return m.group(1) if m else None
def get_desb(desca):
if desca == 'SPARE' or pd.isna(desca) or desca == '':
return ''
tag = str(desca)
prefix = get_prefix(tag)
if 'BCN1_A' in tag:
return 'AMBER BEACON LIGHT'
if 'BCN1_B' in tag:
return 'BLUE BEACON LIGHT'
if 'BCN1' in tag:
if prefix in jam_reset_prefixes:
return '3 STACK IOLINK BEACON'
else:
return '2 STACK IOLINK BEACON'
if 'SOL' in tag:
return 'PKG RELEASE SOLENOID'
if 'PR' in tag:
return 'PKG RELEASE PUSHBUTTON'
if 'PE1' in tag:
return 'FULL PHOTOEYE 50%'
if 'PE2' in tag:
return 'FULL PHOTOEYE 100%'
if 'GS1_PB_LT' in tag or 'GS1_PB' in tag:
return 'CHUTE ENABLE PUSHBUTTON LIGHT'
if 'JR1_PB_LT' in tag:
return 'SORTER JAM RESET PUSHBUTTON LIGHT'
if 'JR1_PB' in tag:
return 'SORTER JAM RESET PUSHBUTTON'
if 'FIOH' in tag:
return 'HUB ARMOR BLOCK'
return ''
for _, row in df.iterrows():
tagname = row['P_TAG1']
for io_col in io_columns:
term = io_col
desca = row.get(io_col, '')
if pd.isna(desca) or desca == '':
desca = 'SPARE'
desb = get_desb(desca)
output_rows.append({'TAGNAME': tagname, 'TERM': term, 'DESCA': desca, 'DESB': desb})
# Output to CSV
output_df = pd.DataFrame(output_rows)
output_df.to_csv('MCM04_IO_EXPANDED.csv', index=False)
print('Output written to MCM04_IO_EXPANDED.csv')

View File

@ -28,21 +28,21 @@ def create_desc_ip_sheet():
xl = pd.ExcelFile(excel_file)
print(f"Available sheets: {xl.sheet_names}")
# Try to find sheets with similar names
# Try to find sheets with specific names
desc_sheet = None
network_sheet = None
for sheet in xl.sheet_names:
if 'DESC' in sheet.upper():
if 'DESC_PLC' in sheet.upper():
desc_sheet = sheet
if 'NETWORK' in sheet.upper():
if 'NETWORK_PLC' in sheet.upper():
network_sheet = sheet
print(f"Found DESC sheet: {desc_sheet}")
print(f"Found NETWORK sheet: {network_sheet}")
if not desc_sheet or not network_sheet:
print("CRITICAL: Required sheets 'DESC...' and 'NETWORK...' not found in the Excel file.")
print("CRITICAL: Required sheets 'DESC_PLC' and 'NETWORK_PLC' not found in the Excel file.")
sys.exit(1)
# Read the sheets
@ -88,58 +88,7 @@ def create_desc_ip_sheet():
shutil.copy2(new_file, "DESC_IP_MERGED.xlsx")
print(f"Created standard output file: DESC_IP_MERGED.xlsx")
# Add minimal safety sheets for Routines Generator compatibility
print("Adding minimal safety sheets for Routines Generator...")
with pd.ExcelWriter("DESC_IP_MERGED.xlsx", mode='a', if_sheet_exists='replace') as writer:
# Create minimal empty safety sheets that LimitedDataLoader expects
# Note: These are minimal empty sheets - the actual safety devices will be extracted from DESC_IP
empty_rst = pd.DataFrame(columns=['TAGNAME', 'DESCA', 'IO_PATH', 'TERM'])
empty_sto = pd.DataFrame(columns=['TAGNAME', 'DESCA', 'IO_PATH', 'TERM'])
empty_epc = pd.DataFrame(columns=['TAGNAME', 'DESCA', 'IO_PATH', 'TERM'])
# Load zones configuration from zones_config.py
print("Loading zones configuration...")
try:
# Import zones configuration
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
from zones_config import ZONES_CONFIGS, DEFAULT_ZONES
# Determine which zones configuration to use based on subsystem
if subsystem in ZONES_CONFIGS:
zones_config = ZONES_CONFIGS[subsystem]
print(f"Using {subsystem} zones configuration")
else:
zones_config = DEFAULT_ZONES
print(f"Using default zones configuration (subsystem {subsystem} not found)")
# Convert zones configuration to DataFrame format
zone_data = []
for zone_config in zones_config:
zone_data.append({
'name': zone_config.get('name', ''),
'start': zone_config.get('start', ''),
'stop': zone_config.get('stop', ''),
'interlock': zone_config.get('interlock', '')
})
zones_df = pd.DataFrame(zone_data)
print(f"Loaded {len(zone_data)} zones: {[z['name'] for z in zone_data]}")
except ImportError as e:
print(f"Warning: Could not load zones_config.py ({e}), falling back to minimal MCM zone")
# Fallback to minimal MCM zone if zones_config.py is not available
zones_df = pd.DataFrame([{
'name': 'MCM',
'start': 'MCM_S_PB',
'stop': 'MCM_EPB_STATUS',
'interlock': ''
}])
empty_rst.to_excel(writer, sheet_name='RST', index=False)
empty_sto.to_excel(writer, sheet_name='STO', index=False)
empty_epc.to_excel(writer, sheet_name='EPC', index=False)
zones_df.to_excel(writer, sheet_name='ZONES', index=False)
print("Added empty RST, STO, EPC, and configured ZONES sheets")
# Do not append legacy safety/ZONES sheets. Step 2 extracts from DESC_IP and uses zones.json.
except Exception as e:
print(f"Error occurred during processing: {e}")

View File

@ -44,7 +44,41 @@ def post_process_io_data(input_file, output_file):
print(f"Removed {len(rows_to_remove_spare_after_fioh)} SPARE rows following FIOH entries")
df = df.drop(rows_to_remove_spare_after_fioh).reset_index(drop=True)
# ------------------------------------------------------------------
# Remove SPARE rows for M12DR devices containing VS
# ------------------------------------------------------------------
m12dr_vs_spare_mask = (
df['TAGNAME'].astype(str).str.contains(r'M12DR', case=False, na=False) &
df['TAGNAME'].astype(str).str.contains(r'VS', case=False, na=False) &
((df['DESCA'].astype(str).str.strip().str.upper() == 'SPARE') |
(df['DESC'].astype(str).str.strip().str.upper() == 'SPARE'))
)
removed_m12dr_vs_spare_count = m12dr_vs_spare_mask.sum()
if removed_m12dr_vs_spare_count:
print(f"Removed {removed_m12dr_vs_spare_count} SPARE rows for M12DR devices containing VS")
df = df[~m12dr_vs_spare_mask].reset_index(drop=True)
# ------------------------------------------------------------------
# Remove SPARE rows that directly follow IOLink entries with SOL in DESCA
# ------------------------------------------------------------------
rows_to_remove_spare_after_iolink_sol = []
for idx in range(len(df) - 1):
try:
current_signal = str(df.at[idx, 'SIGNAL']).strip()
current_desca = str(df.at[idx, 'DESCA']).strip().upper()
next_desc = str(df.at[idx + 1, 'DESC']).strip().upper()
if (current_signal == 'IOLink' and
'SOL' in current_desca and
next_desc == 'SPARE'):
rows_to_remove_spare_after_iolink_sol.append(idx + 1)
except Exception as e:
print(f"Debug: Error at idx {idx}: {e}")
continue
if rows_to_remove_spare_after_iolink_sol:
print(f"Removed {len(rows_to_remove_spare_after_iolink_sol)} SPARE rows following IOLink SOL entries")
df = df.drop(rows_to_remove_spare_after_iolink_sol).reset_index(drop=True)
# Remove ALL IOLink rows and generate beacon light entries first
iolink_mask = df['SIGNAL'] == 'IOLink'

View File

@ -22,7 +22,7 @@ def process_data(desc_df, network_df, original_file, apf_df, m12dr_df, hub_df, s
network_df['NORMALIZED_NAME'] = network_df['Name'].apply(normalize_vfd_name)
if network_df['NORMALIZED_NAME'].duplicated().any():
print("\nWARNING: The following names in the 'NETWORK' sheet become duplicates after normalization (e.g., 'DEV01' and 'DEV1'). Using the first occurrence for IP and PartNumber mapping.")
print("\nWARNING: The following names in the 'NETWORK_PLC' sheet become duplicates after normalization (e.g., 'DEV01' and 'DEV1'). Using the first occurrence for IP and PartNumber mapping.")
duplicated_names = network_df[network_df['NORMALIZED_NAME'].duplicated(keep=False)].sort_values('NORMALIZED_NAME')
print(duplicated_names[['Name', 'NORMALIZED_NAME']].to_string(index=False))
@ -149,11 +149,11 @@ def process_data(desc_df, network_df, original_file, apf_df, m12dr_df, hub_df, s
# Filter out FIOH-containing names for logging
missing_in_network_filtered = {name for name in original_missing_tagnames if 'FIOH' not in str(name).upper()}
if missing_in_network_filtered:
print(f"\nFound {len(missing_in_network_filtered)} TAGNAMEs present in DESC but not in NETWORK.")
print(f"\nFound {len(missing_in_network_filtered)} TAGNAMEs present in DESC but not in NETWORK_PLC.")
for name in sorted(list(missing_in_network_filtered)):
validation_errors.append(f"TAGNAME '{name}' from DESC sheet not found in NETWORK sheet.")
validation_errors.append(f"TAGNAME '{name}' from DESC sheet not found in NETWORK_PLC sheet.")
# Add names from NETWORK that are missing in DESC
# Add names from NETWORK_PLC that are missing in DESC
missing_in_desc_norm = network_names_norm - desc_names_norm
if missing_in_desc_norm:
# Get the original rows from network_df to add, ensuring uniqueness
@ -179,7 +179,7 @@ def process_data(desc_df, network_df, original_file, apf_df, m12dr_df, hub_df, s
missing_dpm_names = dpm_names - all_existing_names
if missing_dpm_names:
print(f"\nAdding unique DPM names not present in DESC or NETWORK.Name: {sorted(missing_dpm_names)}")
print(f"\nAdding unique DPM names not present in DESC or NETWORK_PLC.Name: {sorted(missing_dpm_names)}")
# Create rows for missing DPM names
dpm_rows = []
for dpm_name in missing_dpm_names:

View File

@ -1 +1 @@
MCM_S_PB=SFT_MCM_S_PB, PS1_1_S1_PB=SFT_PS1_1_S1_PB, PS1_1_S2_PB=SFT_PS1_1_S2_PB, PS1_5_S1_PB=SFT_PS1_5_S1_PB, PS1_5_S2_PB=SFT_PS1_5_S2_PB, PS2_1_S1_PB=SFT_PS2_1_S1_PB, PS2_1_S2_PB=SFT_PS2_1_S2_PB, PS2_6_S1_PB=SFT_PS2_6_S1_PB, PS2_6_S2_PB=SFT_PS2_6_S2_PB, PS3_12_S1_PB=SFT_PS3_12_S1_PB, PS3_12_S2_PB=SFT_PS3_12_S2_PB, PS3_1_S1_PB=SFT_PS3_1_S1_PB, PS3_1_S2_PB=SFT_PS3_1_S2_PB, PS4_14_S1_PB=SFT_PS4_14_S1_PB, PS4_14_S2_PB=SFT_PS4_14_S2_PB, PS4_1_S1_PB=SFT_PS4_1_S1_PB, PS4_1_S2_PB=SFT_PS4_1_S2_PB, UL10_1_SS1_SPB=SFT_UL10_1_SS1_SPB, UL10_3_S1_PB=SFT_UL10_3_S1_PB, UL10_3_S2_PB=SFT_UL10_3_S2_PB, UL11_3_S1_PB=SFT_UL11_3_S1_PB, UL11_3_S2_PB=SFT_UL11_3_S2_PB, UL11_4_S1_PB=SFT_UL11_4_S1_PB, UL11_4_S2_PB=SFT_UL11_4_S2_PB, UL11_9_S1_PB=SFT_UL11_9_S1_PB, UL11_9_S2_PB=SFT_UL11_9_S2_PB, UL12_3_S1_PB=SFT_UL12_3_S1_PB, UL12_3_S2_PB=SFT_UL12_3_S2_PB, UL12_4_S1_PB=SFT_UL12_4_S1_PB, UL12_4_S2_PB=SFT_UL12_4_S2_PB, UL1_3_S1_PB=SFT_UL1_3_S1_PB, UL1_3_S2_PB=SFT_UL1_3_S2_PB, UL1_4_S1_PB=SFT_UL1_4_S1_PB, UL1_4_S2_PB=SFT_UL1_4_S2_PB, UL1_9_S1_PB=SFT_UL1_9_S1_PB, UL1_9_S2_PB=SFT_UL1_9_S2_PB, UL2_3_S1_PB=SFT_UL2_3_S1_PB, UL2_3_S2_PB=SFT_UL2_3_S2_PB, UL2_4_S1_PB=SFT_UL2_4_S1_PB, UL2_4_S2_PB=SFT_UL2_4_S2_PB, UL3_1_SS1_SPB=SFT_UL3_1_SS1_SPB, UL3_2_S1_PB=SFT_UL3_2_S1_PB, UL3_2_S2_PB=SFT_UL3_2_S2_PB, UL4_3_S1_PB=SFT_UL4_3_S1_PB, UL4_3_S2_PB=SFT_UL4_3_S2_PB, UL4_4_S1_PB=SFT_UL4_4_S1_PB, UL4_4_S2_PB=SFT_UL4_4_S2_PB, UL4_9_S1_PB=SFT_UL4_9_S1_PB, UL4_9_S2_PB=SFT_UL4_9_S2_PB, UL5_3_S1_PB=SFT_UL5_3_S1_PB, UL5_3_S2_PB=SFT_UL5_3_S2_PB, UL5_4_S1_PB=SFT_UL5_4_S1_PB, UL5_4_S2_PB=SFT_UL5_4_S2_PB, UL6_1_SS1_SPB=SFT_UL6_1_SS1_SPB, UL6_2_S1_PB=SFT_UL6_2_S1_PB, UL6_2_S2_PB=SFT_UL6_2_S2_PB, UL7_3_S1_PB=SFT_UL7_3_S1_PB, UL7_3_S2_PB=SFT_UL7_3_S2_PB, UL7_4_S1_PB=SFT_UL7_4_S1_PB, UL7_4_S2_PB=SFT_UL7_4_S2_PB, UL7_9_S1_PB=SFT_UL7_9_S1_PB, UL7_9_S2_PB=SFT_UL7_9_S2_PB, UL8_1_SS1_SPB=SFT_UL8_1_SS1_SPB, UL8_3_S1_PB=SFT_UL8_3_S1_PB, UL8_3_S2_PB=SFT_UL8_3_S2_PB, UL9_3_S1_PB=SFT_UL9_3_S1_PB, UL9_3_S2_PB=SFT_UL9_3_S2_PB, UL9_4_S1_PB=SFT_UL9_4_S1_PB, UL9_4_S2_PB=SFT_UL9_4_S2_PB
MCM_S_PB=SFT_MCM_S_PB, PS5_1_S1_PB=SFT_PS5_1_S1_PB, PS5_1_S2_PB=SFT_PS5_1_S2_PB, PS6_1_S1_PB=SFT_PS6_1_S1_PB, PS6_1_S2_PB=SFT_PS6_1_S2_PB, PS7_1_S1_PB=SFT_PS7_1_S1_PB, PS7_1_S2_PB=SFT_PS7_1_S2_PB, PS7_9_S1_PB=SFT_PS7_9_S1_PB, PS7_9_S2_PB=SFT_PS7_9_S2_PB, UL13_1_SS1_SPB=SFT_UL13_1_SS1_SPB, UL13_4_S1_PB=SFT_UL13_4_S1_PB, UL13_4_S2_PB=SFT_UL13_4_S2_PB, UL13_8_S1_PB=SFT_UL13_8_S1_PB, UL13_8_S2_PB=SFT_UL13_8_S2_PB, UL14_3_S1_PB=SFT_UL14_3_S1_PB, UL14_3_S2_PB=SFT_UL14_3_S2_PB, UL14_4_S1_PB=SFT_UL14_4_S1_PB, UL14_4_S2_PB=SFT_UL14_4_S2_PB, UL15_3_S1_PB=SFT_UL15_3_S1_PB, UL15_3_S2_PB=SFT_UL15_3_S2_PB, UL15_4_S1_PB=SFT_UL15_4_S1_PB, UL15_4_S2_PB=SFT_UL15_4_S2_PB, UL16_1_SS1_SPB=SFT_UL16_1_SS1_SPB, UL16_2_S1_PB=SFT_UL16_2_S1_PB, UL16_2_S2_PB=SFT_UL16_2_S2_PB, UL17_3_S1_PB=SFT_UL17_3_S1_PB, UL17_3_S2_PB=SFT_UL17_3_S2_PB, UL17_4_S1_PB=SFT_UL17_4_S1_PB, UL17_4_S2_PB=SFT_UL17_4_S2_PB, UL18_10_S1_PB=SFT_UL18_10_S1_PB, UL18_10_S2_PB=SFT_UL18_10_S2_PB, UL18_3_S1_PB=SFT_UL18_3_S1_PB, UL18_3_S2_PB=SFT_UL18_3_S2_PB, UL18_4_S1_PB=SFT_UL18_4_S1_PB, UL18_4_S2_PB=SFT_UL18_4_S2_PB, UL19_1_SS1_SPB=SFT_UL19_1_SS1_SPB, UL19_2_S1_PB=SFT_UL19_2_S1_PB, UL19_2_S2_PB=SFT_UL19_2_S2_PB, UL20_3_S1_PB=SFT_UL20_3_S1_PB, UL20_3_S2_PB=SFT_UL20_3_S2_PB, UL20_4_S1_PB=SFT_UL20_4_S1_PB, UL20_4_S2_PB=SFT_UL20_4_S2_PB, UL21_11_S1_PB=SFT_UL21_11_S1_PB, UL21_11_S2_PB=SFT_UL21_11_S2_PB, UL21_13_S1_PB=SFT_UL21_13_S1_PB, UL21_13_S2_PB=SFT_UL21_13_S2_PB, UL21_3_S1_PB=SFT_UL21_3_S1_PB, UL21_3_S2_PB=SFT_UL21_3_S2_PB, UL21_4_S1_PB=SFT_UL21_4_S1_PB, UL21_4_S2_PB=SFT_UL21_4_S2_PB

View File

@ -1,148 +0,0 @@
<Tag Name="PS1_3_VFD1" Class="Standard" TagType="Base" DataType="UDT_AOI_APF" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[17,0.00000000e+000,0,[0,5000,0],0.00000000e+000,[0,2000,0],0,[0,0,0],0,[9,' STARTING$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[8,' VFD FLT$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[9,' SAFE OFF$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[8,' Running$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[10,' LOST COMM$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,[4,' JAM$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[5,' FULL$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[9,' DISC OFF$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,45000,0],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,0,0.00000000e+000,0,0],[[0],[0,0,0],0,0,0,0,0,0,0,0,0,0,0,0,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,0],[0,0,0,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_APF">
<StructureMember Name="AOI" DataType="AOI_APF">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Disconnect_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Running" DataType="BOOL" Value="0"/>
<DataValueMember Name="Run_Enabled" DataType="BOOL" Value="1"/>
<DataValueMember Name="Run" DataType="BOOL" Value="0"/>
<DataValueMember Name="Maintenance_Running" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStopped" DataType="BOOL" Value="0"/>
<DataValueMember Name="Speed_Not_Set_Up" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Fault_Reset_Required" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Disconnected" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Saving_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_Conveyor" DataType="BOOL" Value="0"/>
<DataValueMember Name="Speed_To_REV_Ratio" DataType="REAL" Radix="Float" Value="0.0"/>
<DataValueMember Name="Maintenance_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stopped_By_Station_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Encoder_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stopped_Require_Start" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stopped_Auto_Restart" DataType="BOOL" Value="0"/>
<DataValueMember Name="Zero_Speed" DataType="BOOL" Value="0"/>
<DataValueMember Name="No_Interlock" DataType="BOOL" Value="0"/>
<DataValueMember Name="MCM_Not_Started" DataType="BOOL" Value="0"/>
<DataValueMember Name="Length" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Horn_O" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_VFD">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_VFD">
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Disconnected" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Reset_Required" DataType="BOOL" Value="0"/>
<DataValueMember Name="Safe_Off_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Maintenance_Mode" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="Maintenance" DataType="UDT_MAINTENANCE_VFD">
<DataValueMember Name="Maintenance_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jog_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Direction_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Direction" DataType="BOOL" Value="0"/>
<DataValueMember Name="Speed_FPM" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Buttons_State" DataType="DINT" Radix="Decimal" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Speed_At_30rev" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Amperage" DataType="INT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Voltage" DataType="INT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Velocity" DataType="INT" Radix="Decimal" Value="0"/>
<DataValueMember Name="FPM" DataType="INT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Cycle_Time_Factor" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Communication_Fault_Code" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="VFD_Fault_Code" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Last_VFD_Fault_Code" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="VFD_Type" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Speed_At_60Hz" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Frequency" DataType="INT" Radix="Decimal" Value="0"/>
<StructureMember Name="Name" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_VFD">
<StructureMember Name="CMD" DataType="UDT_CTRL_VFD_CMD">
<DataValueMember Name="Start" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop_Require_Start" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop_Auto_Restart" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Disable" DataType="BOOL" Value="0"/>
<DataValueMember Name="Run_Up_Enabled" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Saving_Mode_ON" DataType="BOOL" Value="0"/>
<DataValueMember Name="Interlock" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stopped_By_Stop_PB" DataType="BOOL" Value="0"/>
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<StructureMember Name="Acknowledge_Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Encoder_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Speed_FPM" DataType="DINT" Radix="Decimal" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_VFD_STS">
<DataValueMember Name="Running" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Interlock" DataType="BOOL" Value="0"/>
<DataValueMember Name="Current_Speed" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Requested_Speed" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="In_Power_Saving_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="Maintenance_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="MCM_Started" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStopped" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Enabled" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stopped_By_Station_PB" DataType="BOOL" Value="0"/>
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Encoder_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="MCM_JR_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Disabled" DataType="BOOL" Value="0"/>
<DataValueMember Name="MCM_Start_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="MCM_EStop_PB_Pressed" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,105 +0,0 @@
<Tag Name="PDP1_CB_MONITOR" Class="Standard" TagType="Base" DataType="UDT_AOI_CB_MONITOR" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1],[[0,0,0,0]],[[0],[0,0,0,0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_CB_MONITOR">
<StructureMember Name="AOI" DataType="AOI_CB_MONITOR">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="IO_Block_Comm_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB1_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB2_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB3_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB4_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB5_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB6_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB7_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB8_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB9_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB10_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB11_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB12_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB13_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB14_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB15_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB16_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB17_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB18_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB19_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB20_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB21_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB22_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB23_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB24_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB25_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB26_I" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_CB_MONITOR">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_CB_MONITOR">
<DataValueMember Name="Power_Branch_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB1_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB2_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB3_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB4_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB5_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB6_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB7_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB8_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB9_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB10_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB11_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB12_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB13_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB14_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB15_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB16_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB17_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB18_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB19_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB20_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB21_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB22_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB23_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB24_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB25_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB26_Fault" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_CB_MONITOR">
<StructureMember Name="CMD" DataType="UDT_CTRL_CB_MONITOR_CMD">
<DataValueMember Name="Power_Branch_Fault" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_CB_MONITOR_STS">
<DataValueMember Name="Power_Branch_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB1_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB2_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB3_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB4_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB5_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB6_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB7_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB8_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB9_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB10_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB11_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB12_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB13_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB14_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB15_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB16_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB17_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB18_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB19_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB20_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB21_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB22_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB23_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB24_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB25_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="CB26_Fault" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,54 +0,0 @@
<Tag Name="S011003_D2C_CHUTE" Class="Standard" TagType="Base" DataType="UDT_AOI_D2C_CHUTE" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[4194305,0,0,0,0,[1,0,0,[0,0,0],[0,0,0]],[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[0,0,0,0,0,0,0,0]],0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],1,[1,0,0,0,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,3000,0],[0,5000,0],[0,0]],[0,0,0],[0,0,0]],[0,[0],0],[[0],[0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_D2C_CHUTE">
<StructureMember Name="AOI" DataType="AOI_D2C_CHUTE">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="GS_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="GS_PB_Light_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="G_Beacon_Segment_Color_O" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="G_Beacon_Segment_Animation_O" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="B_Beacon_Segment_Color_O" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="B_Beacon_Segment_Animation_O" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Half_Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Busy" DataType="BOOL" Value="0"/>
<DataValueMember Name="Done" DataType="BOOL" Value="0"/>
<DataValueMember Name="Bin_Error" DataType="BOOL" Value="0"/>
<DataValueMember Name="Cyclic_Error" DataType="BOOL" Value="0"/>
<DataValueMember Name="Comms_Error" DataType="BOOL" Value="0"/>
<DataValueMember Name="Cart_Present" DataType="BOOL" Value="0"/>
<DataValueMember Name="Short_Shuttle_Present" DataType="BOOL" Value="0"/>
<DataValueMember Name="Tall_Shuttle_Present" DataType="BOOL" Value="0"/>
<DataValueMember Name="Ready" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_D2C_CHUTE">
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<StructureMember Name="Alarms" DataType="UDT_ALARMS_D2C_CHUTE">
<DataValueMember Name="GS_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Half_Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="No_Container" DataType="BOOL" Value="0"/>
<DataValueMember Name="Disabled" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="GS_PB" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_D2C_CHUTE">
<StructureMember Name="CMD" DataType="UDT_CTRL_D2C_CHUTE_CMD">
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_D2C_CHUTE_STS">
<DataValueMember Name="Enabled" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Ready" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,69 +0,0 @@
<Tag Name="PS1_4_DPM1" Class="Standard" TagType="Base" DataType="UDT_AOI_DPM" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,[0,2000,804],[0,10000,0],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0],[[0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0]],[[0],0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_DPM">
<StructureMember Name="AOI" DataType="AOI_DPM">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="EN4TR_Communication_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_IO_BLOCK">
<StructureMember Name="STS" DataType="UDT_CTRL_IO_BLOCK_STS">
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<StructureMember Name="Acknowledge_Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Unacknowledge_All_Logs" DataType="BOOL" Value="0"/>
<DataValueMember Name="Unacknowldge_All" DataType="BOOL" Value="0"/>
<StructureMember Name="Aknowledgement_ID" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="CMD" DataType="UDT_CTRL_IO_BLOCK_CMD">
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Log_Quantity" DataType="DINT" Radix="Decimal" Value="0"/>
</StructureMember>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_IO_BLOCK">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_IO_BLOCK">
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<StructureMember Name="IP_Address" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<StructureMember Name="Name" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,60 +0,0 @@
<Tag Name="UL11_1_EX1" Class="Standard" TagType="Base" DataType="UDT_AOI_EXTENDO" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,0,[10,' LOST COMM$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[6,' FULL$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0],[0]],[[0],0,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_EXTENDO">
<StructureMember Name="AOI" DataType="AOI_EXTENDO">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="DPM_Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Extendo_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Extendo_Faulted_Reset_Required" DataType="BOOL" Value="0"/>
<DataValueMember Name="Estopped" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Saving_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="No_Interlock" DataType="BOOL" Value="0"/>
<DataValueMember Name="MCM_Not_Started" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_EXTENDO">
<StructureMember Name="CMD" DataType="UDT_CTRL_EXTENDO_CMD">
<DataValueMember Name="Interlock" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_EXTENDO_STS">
<DataValueMember Name="Interlock" DataType="BOOL" Value="0"/>
<DataValueMember Name="Allow_Loading" DataType="BOOL" Value="0"/>
<DataValueMember Name="Running" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_EXTENDO">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_EXTENDO">
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Extendo_Faulted" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Loading_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="Unloading_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="Aopen_Active" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Saving_Mode" DataType="BOOL" Value="0"/>
<DataValueMember Name="Fully_Retracted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Fully_Extended" DataType="BOOL" Value="0"/>
<DataValueMember Name="PEC_Override_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Extendo_Faults_Reset_PB" DataType="BOOL" Value="0"/>
<StructureMember Name="Name" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,70 +0,0 @@
<Tag Name="UL1_13_FIO1" Class="Standard" TagType="Base" DataType="UDT_AOI_IO_BLOCK" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[19,' Lost Communication$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0],0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_IO_BLOCK">
<StructureMember Name="AOI" DataType="AOI_IO_BLOCK">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Fault" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_IO_BLOCK">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_IO_BLOCK">
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<StructureMember Name="IP_Address" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<StructureMember Name="Name" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_IO_BLOCK">
<StructureMember Name="STS" DataType="UDT_CTRL_IO_BLOCK_STS">
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<StructureMember Name="Acknowledge_Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Unacknowledge_All_Logs" DataType="BOOL" Value="0"/>
<DataValueMember Name="Unacknowldge_All" DataType="BOOL" Value="0"/>
<StructureMember Name="Aknowledgement_ID" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="CMD" DataType="UDT_CTRL_IO_BLOCK_CMD">
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Log_Quantity" DataType="DINT" Radix="Decimal" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,45 +0,0 @@
<Tag Name="FL1018_3CH_PE1" Class="Standard" TagType="Base" DataType="UDT_AOI_FPE" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,[0,0,0],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[5,' FULL$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0],0,[14,'FL1018_3CH_PE1$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0],[0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_FPE">
<StructureMember Name="AOI" DataType="AOI_FPE">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Parent_Comm_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Clear_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Blocked" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_PE">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_PE">
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="TimeOut" DataType="DINT" Radix="Decimal" Value="0"/>
<StructureMember Name="Name" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="14"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_PE">
<StructureMember Name="CMD" DataType="UDT_CTRL_PE_CMD">
<DataValueMember Name="Dynamic_Jam" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_PE_STS">
<DataValueMember Name="Blocked" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Chute_Roller_PE" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,47 +0,0 @@
<Tag Name="FL1014_2_PE1" Class="Standard" TagType="Base" DataType="UDT_AOI_JPE" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,[0,0,0],[1,0,0,[0,0,0],[0,0,0]],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[4,' Jam$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,0,0],[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0],0,[12,'FL1014_2_PE1$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0],[0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_JPE">
<StructureMember Name="AOI" DataType="AOI_JPE">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Parent_Comm_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Clear_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Blocked" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Run_Up_PE" DataType="BOOL" Value="0"/>
<DataValueMember Name="Run_Up" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_PE">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_PE">
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="TimeOut" DataType="DINT" Radix="Decimal" Value="0"/>
<StructureMember Name="Name" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="12"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA['FL1014_2_PE1']]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_PE">
<StructureMember Name="CMD" DataType="UDT_CTRL_PE_CMD">
<DataValueMember Name="Dynamic_Jam" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_PE_STS">
<DataValueMember Name="Blocked" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Chute_Roller_PE" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,142 +0,0 @@
<Tag Name="MCM" Class="Standard" TagType="Base" DataType="UDT_AOI_MCM" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,0,[1,0,0,[0,0,0],[0,0,0]],[1,0,0,[0,0,0],[0,0,0]],[1,0,0,[0,0,0],[0,0,0]],[1,0,0,[0,0,0],[0,0,0]],[1,0,0,[0,0,0],[0,0,0]]],[[0,0,0],0,0,0,0,0,0,0,0],[[[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,0,0],[[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0,0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_MCM">
<StructureMember Name="AOI" DataType="AOI_MCM">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Fault_Reset_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Fault_Reset_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Reset_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Restart_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_PB_I_CH1" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_PB_I_CH2" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Fire_Relay_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="On_UPS_Battery_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Battery_Low_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Battery_Fault_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="NAT_Switch_Fault_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Fault_Reset_PB_LT_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Fault_Reset_PB_LT_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Reset_PB_LT_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_Actuated_LT_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_PB_LT_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Restart_PB_LT_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Was_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Was_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Fault_Was_Present" DataType="BOOL" Value="0"/>
<DataValueMember Name="Encoder_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_Was_Actuated" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStopped_Locally" DataType="BOOL" Value="0"/>
<DataValueMember Name="System_Started" DataType="BOOL" Value="0"/>
<DataValueMember Name="Fire_Relay_De_Energized" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Battery_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="On_UPS_Battery" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Battery_Low" DataType="BOOL" Value="0"/>
<DataValueMember Name="NAT_Switch_Fault" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_MCM">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_MCM">
<DataValueMember Name="EStop_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Battery_On" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Battery_Low" DataType="BOOL" Value="0"/>
<DataValueMember Name="Fire_Relay_De_Energized" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Encoder_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStopped" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stopped" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Fault_Reset_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Restart_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Reset_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Fault_Reset_PB_Pressed" DataType="BOOL" Value="0"/>
<DataValueMember Name="UPS_Battery_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="On_UPS_Battery" DataType="BOOL" Value="0"/>
<DataValueMember Name="NAT_Switch_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStopped_Locally" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Motor_Fault_Reset_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Fault_Reset_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Reset_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Restart_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Fault_Reset_PB_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Fault_Reset_PB_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Reset_PB_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_Actuated_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Restart_PB_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_PB_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="Local_Estop_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="Setup_Motor_Speeds" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Fault_Reset_PB_STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Power_Branch_Fault_Reset_PB_STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Reset_PB_STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Start_PB_STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Jam_Restart_PB_STATE" DataType="DINT" Radix="Decimal" Value="0"/>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_MCM">
<StructureMember Name="CMD" DataType="UDT_CTRL_MCM_CMD">
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Log_Quantity" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Acknowledge_Log" DataType="BOOL" Value="0"/>
<DataValueMember Name="Unacknowledge_All_Logs" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Was_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Was_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Fault_Was_Present" DataType="BOOL" Value="0"/>
<DataValueMember Name="Encoder_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_Actuated" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_Was_Actuated" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Fault" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_MCM_STS">
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Log_Quantity" DataType="DINT" Radix="Decimal" Value="0"/>
<StructureMember Name="Acknowledge_Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="Unacknowledge_All_Logs" DataType="BOOL" Value="0"/>
<DataValueMember Name="Motor_Was_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="VFD_Fault_Reset_Requested" DataType="BOOL" Value="0"/>
<DataValueMember Name="Power_Branch_Fault_Reset_Requested" DataType="BOOL" Value="0"/>
<DataValueMember Name="Low_Air_Pressure_Fault_Reset_Requested" DataType="BOOL" Value="0"/>
<DataValueMember Name="System_Started" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Reset_Requested" DataType="BOOL" Value="0"/>
<DataValueMember Name="Communication_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Setup_Motor_Speeds" DataType="BOOL" Value="0"/>
<DataValueMember Name="System_Start_Requested" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,62 +0,0 @@
<Tag Name="S011004_PB_Chute" Class="Standard" TagType="Base" DataType="UDT_AOI_PB_CHUTE" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,0,0,0,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],[0,0,0],[0,0,0],[1,0,0,[0,0,0],[0,0,0]]],[[0],0,0,0,0,0],[[0],[0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_PB_CHUTE">
<StructureMember Name="AOI" DataType="AOI_PB_CHUTE">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="IO_Block_Communication_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Half_Full_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="PR_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Half_Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Disabled" DataType="BOOL" Value="0"/>
<DataValueMember Name="Solenoid_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="G_Beacon_Segment_Color" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="G_Beacon_Segment_Animation" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="B_Beacon_Segment_Color" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="B_Beacon_Segment_Animation" DataType="DINT" Radix="Decimal" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_PB_CHUTE">
<StructureMember Name="Alarms" DataType="UDT_ALARMS_PB_CHUTE">
<DataValueMember Name="Disabled" DataType="BOOL" Value="0"/>
<DataValueMember Name="Half_Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam" DataType="BOOL" Value="0"/>
<DataValueMember Name="PR_PB_Pressed" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Enable_Chute_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="TimeOut" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="PR_PB_STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Chute_Type" DataType="DINT" Radix="Decimal" Value="0"/>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_PB_CHUTE">
<StructureMember Name="CMD" DataType="UDT_CTRL_PB_CHUTE_CMD">
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Half_Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_PB_CHUTE_STS">
<DataValueMember Name="Enabled" DataType="BOOL" Value="0"/>
<DataValueMember Name="Half_Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full" DataType="BOOL" Value="0"/>
<DataValueMember Name="Full_PE_Blocked" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Ready" DataType="BOOL" Value="0"/>
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,26 +0,0 @@
<Tag Name="PDP1_PMM1" Class="Standard" TagType="Base" DataType="UDT_AOI_PMM" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,[0,0.00000000e+000,0.00000000e+000,0.00000000e+000,[0]]],[0,0.00000000e+000,0.00000000e+000,0.00000000e+000
,[0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_PMM">
<StructureMember Name="AOI" DataType="AOI_PMM">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Parent_Comm_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="PMM_Fault_I" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_PMM">
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="PMM_Total_Power" DataType="REAL" Radix="Float" Value="0.0"/>
<DataValueMember Name="PMM_KWH_Consumed" DataType="REAL" Radix="Float" Value="0.0"/>
<DataValueMember Name="PMM_Max_Total_Power" DataType="REAL" Radix="Float" Value="0.0"/>
<StructureMember Name="Alarm" DataType="UDT_ALARMS_PMM">
<DataValueMember Name="PMM_Communication_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="PMM_Fault" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,25 +0,0 @@
<Tag Name="Rack" Class="Standard" TagType="Base" DataType="UDT_AOI_RACK" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,0,0,0,0,0],[[0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_RACK">
<StructureMember Name="AOI" DataType="AOI_RACK">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="Slot2_EN4TR_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Slot5_IB16_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Slot6_OB16E_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Slot7_IB16S_Faulted" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_RACK">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_RACK">
<DataValueMember Name="Slot5_IB16_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Slot6_OB16E_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Slot7_IB16S_Faulted" DataType="BOOL" Value="0"/>
<DataValueMember Name="Slot2_EN4TR_Faulted" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,35 +0,0 @@
<Tag Name="S011003_JR" Class="Standard" TagType="Base" DataType="UDT_AOI_STATION_JR_CHUTE" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,0,0,[1,0,0,[0,0,0],[0,0,0]]],[[0],0,0],[[0],[0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_STATION_JR_CHUTE">
<StructureMember Name="AOI" DataType="AOI_STATION_JR_CHUTE">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="JR_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="JR_PB_LT_O" DataType="BOOL" Value="0"/>
<DataValueMember Name="A_Beacon_Segment_Color_O" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="A_Beacon_Segment_Animation_O" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_STATION_JR_CHUTE">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_STATION_JR_CHUTE">
<DataValueMember Name="Pressed" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="JR_PB" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_STATION_JR_CHUTE">
<StructureMember Name="CMD" DataType="UDT_CTRL_STATION_JR_CHUTE_CMD">
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="Sorter_JPE_Blocked" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_STATION_JR_CHUTE_STS">
<DataValueMember Name="Jam_Reset_Requested" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -1,62 +0,0 @@
<Tag Name="FL1014_2_JR2_PB" Class="Standard" TagType="Base" DataType="UDT_AOI_STATION_JR_PB" Constant="false" ExternalAccess="Read/Write" OpcUaAccess="None">
<Data Format="L5K">
<![CDATA[[[1,0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0],0,0,[15,'FL1014_2_JR2_PB$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[[0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
]],[0,[0,'$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00'
],0]]]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="UDT_AOI_STATION_JR_PB">
<StructureMember Name="AOI" DataType="AOI_STATION_JR_PB">
<DataValueMember Name="EnableIn" DataType="BOOL" Value="1"/>
<DataValueMember Name="EnableOut" DataType="BOOL" Value="0"/>
<DataValueMember Name="JR_PB_I" DataType="BOOL" Value="0"/>
<DataValueMember Name="JR_PB_LT_O" DataType="BOOL" Value="0"/>
</StructureMember>
<StructureMember Name="HMI" DataType="UDT_HMI_STATION">
<StructureMember Name="Alarm" DataType="UDT_ALARMS_STATION">
<DataValueMember Name="EStopped" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stopped" DataType="BOOL" Value="0"/>
<DataValueMember Name="Pressed" DataType="BOOL" Value="0"/>
</StructureMember>
<DataValueMember Name="STATE" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="JR_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Start_PB" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop_PB" DataType="BOOL" Value="0"/>
<StructureMember Name="Name" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="15"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="CTRL" DataType="UDT_CTRL_STATION">
<StructureMember Name="CMD" DataType="UDT_CTRL_STATION_CMD">
<DataValueMember Name="Jammed" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_Actuated" DataType="BOOL" Value="0"/>
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
</StructureMember>
<StructureMember Name="STS" DataType="UDT_CTRL_STATION_STS">
<DataValueMember Name="Start" DataType="BOOL" Value="0"/>
<DataValueMember Name="Stop" DataType="BOOL" Value="0"/>
<DataValueMember Name="EStop_Was_Actuated" DataType="BOOL" Value="0"/>
<StructureMember Name="Log" DataType="STRING">
<DataValueMember Name="LEN" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="DATA" DataType="STRING" Radix="ASCII">
<![CDATA[]]>
</DataValueMember>
</StructureMember>
<DataValueMember Name="JR_PB_LT" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Fault" DataType="BOOL" Value="0"/>
<DataValueMember Name="Jam_Reset" DataType="BOOL" Value="0"/>
</StructureMember>
</StructureMember>
</Structure>
</Data>
</Tag>

View File

@ -18,6 +18,7 @@ import io
import contextlib
import xml.etree.ElementTree as ET
import re
from datetime import datetime
def get_project_paths():
"""Get standardized paths for all project components."""
@ -31,7 +32,100 @@ def get_project_paths():
'io_tree_generator': project_root / "IO Tree Configuration Generator"
}
def run_plc_data_generator(raw_excel_file: Path, paths: dict, verbose: bool = False) -> bool:
def resolve_project_config_files(project_name: str, project_root: Path) -> tuple[Path, Path]:
"""Resolve configuration file paths based on project name.
Args:
project_name: Project name (e.g., 'MTN6_MCM02', 'SAT9_MCM01', 'CNO8_MCM01')
project_root: Root directory of the project
Returns:
tuple: (generator_config_path, zones_config_path)
Raises:
FileNotFoundError: If required config files don't exist
"""
# Extract project prefix (MTN6, SAT9, CNO8, etc.)
import re
project_match = re.match(r'^([A-Z0-9]+)_', project_name.upper())
if not project_match:
raise ValueError(f"Invalid project name format: {project_name}. Expected format: PREFIX_MCMXX")
project_prefix = project_match.group(1)
# Build config file paths
generator_config = project_root / f"{project_prefix}_generator_config.json"
zones_config = project_root / f"{project_prefix}_zones.json"
# Validate files exist
if not generator_config.exists():
raise FileNotFoundError(f"Generator config not found: {generator_config}")
if not zones_config.exists():
raise FileNotFoundError(f"Zones config not found: {zones_config}")
return generator_config, zones_config
def get_available_projects(project_root: Path) -> list[str]:
"""Get list of available project prefixes based on config files.
Args:
project_root: Root directory of the project
Returns:
List of available project prefixes (e.g., ['MTN6', 'SAT9', 'CNO8'])
"""
import re
projects = set()
# Look for *_generator_config.json files
for config_file in project_root.glob("*_generator_config.json"):
match = re.match(r'^([A-Z0-9]+)_generator_config\.json$', config_file.name)
if match:
prefix = match.group(1)
# Check if corresponding zones file exists
zones_file = project_root / f"{prefix}_zones.json"
if zones_file.exists():
projects.add(prefix)
return sorted(list(projects))
def resolve_boilerplate_directory(project_prefix: str, io_tree_dir: Path) -> str:
"""Resolve the boilerplate directory based on project prefix.
Args:
project_prefix: Project prefix (e.g., 'MTN6', 'SAT9', 'CNO8')
io_tree_dir: IO Tree Configuration Generator directory
Returns:
Boilerplate directory name (e.g., 'MTN6_boilerplate')
"""
boilerplate_dir = f"{project_prefix}_boilerplate"
boilerplate_path = io_tree_dir / boilerplate_dir
if boilerplate_path.exists():
return boilerplate_dir
else:
# Fall back to default boilerplate directory
print(f"Warning: Project-specific boilerplate directory not found: {boilerplate_dir}")
print(" Using default 'boilerplate' directory")
return "boilerplate"
def _append_log(log_path: Path | None, header: str, body: str) -> None:
if not log_path:
return
try:
log_path.parent.mkdir(parents=True, exist_ok=True)
with open(log_path, 'a', encoding='utf-8') as f:
f.write(f"\n=== {header} ===\n")
if body:
f.write(body)
if not body.endswith("\n"):
f.write("\n")
except Exception:
pass
def run_plc_data_generator(raw_excel_file: Path, paths: dict, verbose: bool = False, log_file: Path | None = None) -> bool:
"""Run the PLC Data Generator to create DESC_IP_MERGED.xlsx."""
data_gen_dir = paths['data_generator']
data_gen_script = data_gen_dir / "main.py"
@ -64,9 +158,10 @@ def run_plc_data_generator(raw_excel_file: Path, paths: dict, verbose: bool = Fa
# Consider it successful if the essential files were created, even with permission errors
if result.returncode == 0 or (any(success_indicators) and "[Errno 1] Operation not permitted" in result.stdout):
if verbose and result.returncode != 0:
print("Warning: Permission error at end of processing, core processing completed")
_append_log(log_file, "Step 1 Warning", "Permission error at end of processing, core processing completed")
if verbose:
print(result.stdout)
_append_log(log_file, "Step 1: PLC Data Generator stdout", result.stdout)
_append_log(log_file, "Step 1: PLC Data Generator stderr", result.stderr)
# Copy DESC_IP_MERGED.xlsx from data generator output (it already has safety sheets)
dest = paths['routines_generator'] / "DESC_IP_MERGED.xlsx"
@ -79,28 +174,33 @@ def run_plc_data_generator(raw_excel_file: Path, paths: dict, verbose: bool = Fa
return False
else:
if verbose:
print("Error: Data processing failed")
print("STDOUT:", result.stdout)
print("STDERR:", result.stderr)
_append_log(log_file, "Step 1 Error", "Data processing failed")
_append_log(log_file, "Step 1: PLC Data Generator stdout", result.stdout)
_append_log(log_file, "Step 1: PLC Data Generator stderr", result.stderr)
return False
except Exception as e:
if verbose:
print(f"Error: Exception in data processing: {e}")
_append_log(log_file, "Step 1 Exception", str(e))
return False
def run_routines_generator(paths: dict, project_name: str = None, ignore_estop1ok: bool = False, safety_only: bool = False, verbose: bool = False) -> bool:
def run_routines_generator(paths: dict, project_name: str = None, ignore_estop1ok: bool = False, safety_only: bool = False, verbose: bool = False, log_file: Path | None = None, config_path: Path = None) -> bool:
"""Run the Routines Generator.
When safety_only is True, runs safety-only generation (inputs, outputs, resets,
estops, zones, estop_check, safety tag map). Otherwise runs the standard
generator with DPM and other routines.
Args:
config_path: Path to project-specific generator config file. If None, uses default.
"""
routines_dir = paths['routines_generator']
try:
# Build command arguments to use unified, config-driven CLI
# Use provided config path or fall back to default
if config_path is None:
config_path = paths['project_root'] / 'generator_config.json'
excel_path = routines_dir / 'DESC_IP_MERGED.xlsx'
subcmd = 'safety' if safety_only else 'all'
# Build args with global flags BEFORE the subcommand
@ -112,6 +212,8 @@ def run_routines_generator(paths: dict, project_name: str = None, ignore_estop1o
]
if verbose:
cmd_args.extend(['--log-level', 'DEBUG'])
if log_file is not None:
cmd_args.extend(['--log-file', str(log_file)])
cmd_args.append(subcmd)
# Note: routine inclusion/exclusion is driven by config; project_name and ignore-estop1ok are configured in JSON
@ -119,9 +221,9 @@ def run_routines_generator(paths: dict, project_name: str = None, ignore_estop1o
result = subprocess.run(cmd_args, cwd=routines_dir, capture_output=True, text=True)
if verbose:
print(result.stdout)
_append_log(log_file, "Step 2: Routines Generator stdout", result.stdout)
if result.stderr:
print("[generator stderr]", result.stderr)
_append_log(log_file, "Step 2: Routines Generator stderr", result.stderr)
if result.returncode == 0:
return True
@ -130,10 +232,10 @@ def run_routines_generator(paths: dict, project_name: str = None, ignore_estop1o
except Exception as e:
if verbose:
print(f"Error: Exception in routine generation: {e}")
_append_log(log_file, "Step 2 Exception", str(e))
return False
def run_io_tree_generator(paths: dict, project_name: str, safety_only: bool = False, verbose: bool = False) -> bool:
def run_io_tree_generator(paths: dict, project_name: str, safety_only: bool = False, verbose: bool = False, log_file: Path | None = None, boilerplate_dir: str = None) -> bool:
"""Run the IO Tree Configuration Generator.
If safety_only is True, skip this step to avoid generating non-safety routines.
@ -161,15 +263,17 @@ def run_io_tree_generator(paths: dict, project_name: str, safety_only: bool = Fa
project_name
]
# Zones removed; no additional args
# Add boilerplate directory if specified
if boilerplate_dir:
cmd_args.append(boilerplate_dir)
# Run the IO Tree Configuration Generator
result = subprocess.run(cmd_args, cwd=io_tree_dir, capture_output=True, text=True)
if verbose:
print(result.stdout)
_append_log(log_file, "Step 3: IO Tree Generator stdout", result.stdout)
if result.stderr:
print("[io-tree stderr]", result.stderr)
_append_log(log_file, "Step 3: IO Tree Generator stderr", result.stderr)
if result.returncode == 0:
return True
@ -178,10 +282,10 @@ def run_io_tree_generator(paths: dict, project_name: str, safety_only: bool = Fa
except Exception as e:
if verbose:
print(f"Error: Exception in IO tree generation: {e}")
_append_log(log_file, "Step 3 Exception", str(e))
return False
def run_l5x_to_acd_compiler(paths: dict, project_name: str, safety_only: bool = False, verbose: bool = False) -> bool:
def run_l5x_to_acd_compiler(paths: dict, project_name: str, safety_only: bool = False, verbose: bool = False, log_file: Path | None = None) -> bool:
"""Prepare for L5X2ACD Compilation using dynamic compilation manager.
If safety_only is True, skip this step since a full project L5X wasn't generated.
@ -200,31 +304,23 @@ def run_l5x_to_acd_compiler(paths: dict, project_name: str, safety_only: bool =
l5x_files = list(generated_projects_dir.glob(f"{project_name}*.L5X"))
if not l5x_files:
if verbose:
available_files = list(generated_projects_dir.glob("*.L5X"))
if available_files:
print(f"Available L5X files: {[f.name for f in available_files]}")
# Minimal output: rely on caller to report FAIL
return False
if len(l5x_files) > 1 and verbose:
print(f"Warning: Multiple L5X files found, using first: {l5x_files[0].name}")
complete_l5x = l5x_files[0]
if verbose:
print(f"Found generated L5X file: {complete_l5x.name}")
# Inject SafetyTagMap from SafetyTagMapping.txt before compilation (if available)
try:
mapping_file = paths['routines_generator'] / 'SafetyTagMapping.txt'
if mapping_file.exists():
if verbose:
print("Injecting SafetyTagMap from SafetyTagMapping.txt into L5X ...")
_inject_safety_tag_map_into_l5x(complete_l5x, mapping_file, verbose)
elif verbose:
print("SafetyTagMapping.txt not found; skipping SafetyTagMap injection")
# Always inject silently (minimal logging)
_inject_safety_tag_map_into_l5x(complete_l5x, mapping_file, False)
except Exception as e:
if verbose:
print(f"Warning: Failed to inject SafetyTagMap: {e}")
_append_log(log_file, "Step 4 Warning", f"Failed to inject SafetyTagMap: {e}")
# Use the dynamic compilation manager
l5x2acd_dir = paths['project_root'] / "L5X2ACD Compiler"
@ -238,10 +334,9 @@ def run_l5x_to_acd_compiler(paths: dict, project_name: str, safety_only: bool =
# Create compilation manager
manager = CompilationManager(l5x2acd_dir)
# Determine project-specific options
# Determine project-specific options (silent)
project_type = "UNKNOWN"
options = {}
if project_name:
if "MCM01" in project_name.upper():
project_type = "MCM01"
@ -250,18 +345,8 @@ def run_l5x_to_acd_compiler(paths: dict, project_name: str, safety_only: bool =
project_type = "MCM04"
options['enable_feeder_optimization'] = True
if verbose:
print(f"- Project type: {project_type}")
# Setup compilation with wipe and dynamic generation
if verbose:
result = manager.setup_compilation(
source_l5x=complete_l5x,
project_name=project_name or complete_l5x.stem,
compilation_options=options,
wipe_existing=True
)
else:
# Always run quietly and suppress tool output; caller prints step OK/FAIL
_buf = io.StringIO()
with contextlib.redirect_stdout(_buf), contextlib.redirect_stderr(_buf):
result = manager.setup_compilation(
@ -270,22 +355,13 @@ def run_l5x_to_acd_compiler(paths: dict, project_name: str, safety_only: bool =
compilation_options=options,
wipe_existing=True
)
if verbose:
print("OK: Compilation setup completed")
l5x2acd_windows_path = str(l5x2acd_dir).replace('/mnt/c/', 'C:\\').replace('/', '\\')
l5x_windows_path = str(result['l5x_file']).replace('/mnt/c/', 'C:\\').replace('/', '\\')
print("To compile on Windows:")
print(f"- cd \"{l5x2acd_windows_path}\"")
print(f"- python l5x_to_acd.py \"{l5x_windows_path}\"")
_append_log(log_file, "Step 4: L5X2ACD Compiler output", _buf.getvalue())
return True
except Exception as e:
if verbose:
print(f"Error: Exception in compilation setup: {e}")
import traceback
traceback.print_exc()
# Minimal output; let caller handle FAIL display
return False
@ -369,43 +445,165 @@ def main() -> None:
"""Main entry point for complete workflow."""
parser = argparse.ArgumentParser(description="Complete PLC generation workflow from raw Excel to ACD")
parser.add_argument('--excel-file', type=Path, required=True, help='Raw Excel file to process')
parser.add_argument('--project-name', help='Project name (for compatibility)')
parser.add_argument('--excel-file', type=Path, help='Raw Excel file to process')
# Project selection
parser.add_argument('--project', help='Project prefix (e.g., MTN6, SAT9, CNO8) - automatically selects config files')
parser.add_argument('--project-name', help='Project name (e.g., MTN6_MCM02) - used for output naming and compatibility')
parser.add_argument('--ignore-estop1ok', action='store_true', help='Ignore ESTOP1OK tags in safety routines generation')
parser.add_argument('--safety-only', action='store_true', help='Generate only safety routines and safety checks')
parser.add_argument('--verbose', action='store_true', help='Print detailed logs for each step')
parser.add_argument('--verbose', action='store_true', help='Write detailed logs for each step to a file (no console spam)')
parser.add_argument('--list-projects', action='store_true', help='List available projects and exit')
args = parser.parse_args()
# Get project paths
paths = get_project_paths()
# Handle --list-projects (allow without --excel-file)
if args.list_projects:
available_projects = get_available_projects(paths['project_root'])
print("Available projects:")
for project in available_projects:
generator_config = paths['project_root'] / f"{project}_generator_config.json"
zones_config = paths['project_root'] / f"{project}_zones.json"
boilerplate_dir = paths['io_tree_generator'] / f"{project}_boilerplate"
boilerplate_status = "" if boilerplate_dir.exists() else ""
print(f" {project:<6} - Config: {generator_config.name}, Zones: {zones_config.name}, Boilerplate: {boilerplate_status}")
if not available_projects:
print(" No projects found. Expected files: PREFIX_generator_config.json and PREFIX_zones.json")
return
# Resolve project configuration
generator_config_path = None
zones_config_path = None
project_name = args.project_name # Use provided project name if given
if args.project:
# Project selection mode - use project prefix to find config files
try:
# If no project name provided, derive it from Excel file name
if not project_name:
excel_name = args.excel_file.stem
if 'MCM' in excel_name.upper():
# Try to extract MCM info from filename
import re
mcm_match = re.search(r'(MCM\d+)', excel_name.upper())
if mcm_match:
project_name = f"{args.project.upper()}_{mcm_match.group(1)}"
else:
project_name = f"{args.project.upper()}_MCM01" # Default fallback
else:
project_name = f"{args.project.upper()}_MCM01" # Default fallback
# Use project prefix to find config files, but use provided or derived project name
generator_config_path, zones_config_path = resolve_project_config_files(f"{args.project.upper()}_MCM01", paths['project_root'])
print(f"Using project: {args.project.upper()}")
print(f" Generator config: {generator_config_path.name}")
print(f" Zones config: {zones_config_path.name}")
print(f" Project name: {project_name}")
except (ValueError, FileNotFoundError) as e:
print(f"Error: {e}")
available_projects = get_available_projects(paths['project_root'])
if available_projects:
print(f"Available projects: {', '.join(available_projects)}")
else:
print("No projects found. Run with --list-projects to see details.")
sys.exit(1)
elif args.project_name:
# Backward compatibility mode using --project-name only
project_name = args.project_name
# Try to auto-detect config files based on project name
try:
generator_config_path, zones_config_path = resolve_project_config_files(project_name, paths['project_root'])
print(f"Auto-detected config files for {project_name}:")
print(f" Generator config: {generator_config_path.name}")
print(f" Zones config: {zones_config_path.name}")
except (ValueError, FileNotFoundError):
# Fall back to default config files
print(f"Using default config files (project-specific configs not found for {project_name})")
generator_config_path = None # Will use default in run_routines_generator
else:
# No project specified - require at least one
print("Error: Either --project or --project-name must be specified")
available_projects = get_available_projects(paths['project_root'])
if available_projects:
print(f"Available projects: {', '.join(available_projects)}")
sys.exit(1)
# Validate excel-file is provided for actual processing (not just listing)
if not args.excel_file:
print("Error: --excel-file is required for processing")
parser.print_help()
sys.exit(1)
# Setup enhanced logging
from src.logging_config import setup_logging, get_logger
ts = datetime.now().strftime('%Y%m%d_%H%M%S')
log_dir = paths['project_root'] / 'logs'
base = project_name or 'project'
log_file = log_dir / f"workflow_{base}_{ts}.log" if args.verbose else None
# Configure logging with location information
setup_logging(
level='DEBUG' if args.verbose else 'INFO',
console_format='human',
log_file=log_file,
show_module=True,
show_location=True,
use_colors=True
)
logger = get_logger(__name__)
logger.info("PLC Generation Workflow started", excel_file=str(args.excel_file), project_name=args.project_name)
print("PLC Generation Workflow")
# Step 1: Process raw Excel data
print("Step 1: Data processing ...", end=" ")
ok = run_plc_data_generator(args.excel_file, paths, verbose=args.verbose)
logger.info("Starting data processing step")
try:
ok = run_plc_data_generator(args.excel_file, paths, verbose=args.verbose, log_file=log_file)
print("OK" if ok else "FAIL")
if not ok:
logger.error("Data processing failed")
if not args.verbose:
print("(details suppressed; re-run with --verbose)")
sys.exit(1)
logger.info("Data processing completed successfully")
except Exception as e:
logger.exception("Data processing step failed with exception", error=str(e))
print("FAIL")
sys.exit(1)
# Step 2: Generate L5X programs (Routines Generator)
print("Step 2: Routine generation ...", end=" ")
ok = run_routines_generator(paths, args.project_name, args.ignore_estop1ok, args.safety_only, verbose=args.verbose)
logger.info("Starting routine generation step")
try:
ok = run_routines_generator(paths, project_name, args.ignore_estop1ok, args.safety_only, verbose=args.verbose, log_file=log_file, config_path=generator_config_path)
print("OK" if ok else "FAIL")
if not ok:
logger.error("Routine generation failed")
if not args.verbose:
print("(details suppressed; re-run with --verbose)")
sys.exit(1)
logger.info("Routine generation completed successfully")
except Exception as e:
logger.exception("Routine generation step failed with exception", error=str(e))
print("FAIL")
sys.exit(1)
# Step 3: Generate complete project L5X (IO Tree Generator)
if args.safety_only:
print("Step 3: IO tree generation ... SKIPPED")
else:
print("Step 3: IO tree generation ...", end=" ")
ok = run_io_tree_generator(paths, args.project_name, args.safety_only, verbose=args.verbose)
# Determine boilerplate directory based on project
boilerplate_dir = None
if args.project:
boilerplate_dir = resolve_boilerplate_directory(args.project.upper(), paths['io_tree_generator'])
ok = run_io_tree_generator(paths, project_name, args.safety_only, verbose=args.verbose, log_file=log_file, boilerplate_dir=boilerplate_dir)
print("OK" if ok else "FAIL")
if not ok:
if not args.verbose:
@ -417,7 +615,7 @@ def main() -> None:
print("Step 4: Prepare compilation ... SKIPPED")
else:
print("Step 4: Prepare compilation ...", end=" ")
ok = run_l5x_to_acd_compiler(paths, args.project_name, args.safety_only, verbose=args.verbose)
ok = run_l5x_to_acd_compiler(paths, project_name, args.safety_only, verbose=args.verbose, log_file=log_file)
print("OK" if ok else "FAIL")
if not ok:
if not args.verbose:
@ -425,8 +623,10 @@ def main() -> None:
sys.exit(1)
print("Workflow complete")
if args.verbose and not args.safety_only and args.project_name:
print(f"L5X: IO Tree Configuration Generator/generated_projects/{args.project_name}.L5X")
if args.verbose and log_file is not None:
print(f"Logs: {log_file}")
if not args.safety_only and project_name:
print(f"L5X: IO Tree Configuration Generator/generated_projects/{project_name}.L5X")
if __name__ == '__main__':
main()

View File

@ -1,8 +0,0 @@
#!/usr/bin/env python3
"""
This script is deprecated. Use the unified CLI:
python -m src.unified_cli --config ../generator_config.json --excel-file DESC_IP_MERGED.xlsx all
"""
import sys
print("generate_all.py is deprecated. Please use the unified CLI (src.unified_cli).", file=sys.stderr)
sys.exit(1)

View File

@ -1,135 +0,0 @@
#!/usr/bin/env python3
"""
PLC Routines Generator - Main Entry Point
This script provides backward compatibility while using the new unified CLI internally.
For new usage, prefer the unified CLI: python -m src.unified_cli
"""
from __future__ import annotations
import sys
import argparse
from pathlib import Path
import subprocess
def run_l5x_to_acd_compilation(safety_l5x: Path, main_l5x: Path) -> bool:
"""Run the L5X to ACD compilation step."""
l5x2acd_dir = Path("../L5X2ACD Compiler")
l5x2acd_script = l5x2acd_dir / "l5x_to_acd.py"
if not l5x2acd_script.exists():
print(f"ERROR: L5X2ACD compiler not found at {l5x2acd_script}")
return False
if not safety_l5x.exists():
print(f"ERROR: SafetyProgram L5X not found at {safety_l5x}")
return False
if not main_l5x.exists():
print(f"ERROR: MainProgram L5X not found at {main_l5x}")
return False
print(f"\n=== Compiling L5X files to ACD ===")
print(f"Safety L5X: {safety_l5x}")
print(f"Main L5X: {main_l5x}")
try:
# Run the L5X2ACD compiler
result = subprocess.run([
sys.executable,
str(l5x2acd_script),
str(safety_l5x.resolve()),
str(main_l5x.resolve())
], cwd=l5x2acd_dir, capture_output=True, text=True)
if result.returncode == 0:
print("SUCCESS: L5X to ACD compilation completed successfully")
print(result.stdout)
return True
else:
print("ERROR: L5X to ACD compilation failed")
print("STDOUT:", result.stdout)
print("STDERR:", result.stderr)
return False
except Exception as e:
print(f"ERROR: Error running L5X2ACD compiler: {e}")
return False
def main() -> None:
"""Main entry point that maps old generate_all.py behavior to new unified CLI."""
# Parse arguments to maintain backward compatibility
parser = argparse.ArgumentParser(description="Generate PLC routine artifacts")
parser.add_argument('--config', type=Path, default=Path(__file__).parent.parent / 'generator_config.json', help='Configuration file')
parser.add_argument('--excel-file', type=Path, help='Excel file to process')
parser.add_argument('--output-dir', type=Path, help='Output directory')
parser.add_argument('--log-level', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'], default='INFO', help='Log level')
parser.add_argument('--log-file', type=Path, help='Log file path')
parser.add_argument('--project-name', help='Project name (for compatibility, not used)')
# Zones option removed
# New compilation option
parser.add_argument('--compile-acd', action='store_true', help='Compile L5X files to ACD after generation')
# Legacy argument for compatibility
parser.add_argument('--desc-ip-mode', action='store_true', help='(Deprecated) DESC_IP extraction is now the default')
args = parser.parse_args()
if args.desc_ip_mode:
print("WARNING: --desc-ip-mode flag is deprecated. DESC_IP extraction is now the default mode.")
# Construct arguments for unified CLI
unified_args = ['--log-level', args.log_level]
if args.config:
unified_args.extend(['--config', str(args.config)])
if args.excel_file:
unified_args.extend(['--excel-file', str(args.excel_file)])
# Zones option removed
# Add the 'all' command
unified_args.append('all')
if args.output_dir:
unified_args.extend(['--output-dir', str(args.output_dir)])
# Import and call the unified CLI
from src.unified_cli import main as unified_main
print("=== PLC Routines Generator (Refactored) ===")
print("Using unified CLI internally...")
print()
try:
# Generate L5X files
unified_main(unified_args)
# If compilation requested, run L5X2ACD compiler
if args.compile_acd:
# Determine output directory
output_dir = args.output_dir or Path('.')
safety_l5x = output_dir / "SafetyProgram_Generated.L5X"
main_l5x = output_dir / "MainProgram_Generated.L5X"
success = run_l5x_to_acd_compilation(safety_l5x, main_l5x)
if not success:
print("\nERROR: Compilation failed")
sys.exit(1)
else:
print("\nSUCCESS: Complete PLC generation and compilation successful!")
else:
print("\nSUCCESS: L5X generation completed. Use --compile-acd to also generate ACD files.")
except SystemExit as e:
if e.code != 0:
print(f"\nERROR: Generation failed with exit code {e.code}")
sys.exit(e.code)
if __name__ == '__main__':
main()

View File

@ -30,6 +30,8 @@ class BaseGenerator(ABC):
# Will be set during generation
self.builder: Optional[L5XBuilder] = None
self.routine_manager: Optional[RoutineManager] = None
# Metrics for summary logging
self.metrics: Dict[str, Any] = {}
def generate(self) -> ET.Element:
"""Template method for generating PLC programs.
@ -102,7 +104,46 @@ class BaseGenerator(ABC):
def finalize_generation(self) -> None:
"""Finalize the generation process. Override if needed."""
pass
# Default: log a concise program summary
try:
self._log_program_summary()
except Exception:
# Summary is best-effort; do not break generation
return
def _log_program_summary(self) -> None:
if not self.builder:
return
routines_el = self.builder.get_routines_section()
program_el = self.builder.get_program_element()
# Collect routines
routines = [r.get('Name', '') for r in routines_el.findall('Routine')]
routines = [r for r in routines if r]
routines.sort()
if routines:
self.logger.info(f"Routines created ({len(routines)}): {', '.join(routines)}", stage="summary")
# For each routine, log rung count and one example rung text (first non-empty)
for r in routines_el.findall('Routine'):
name = r.get('Name', '')
rll = r.find('RLLContent')
if rll is None:
continue
rungs = rll.findall('Rung')
rung_count = len(rungs)
example = ''
for rung in rungs:
txt = rung.find('Text')
if txt is not None and (txt.text or '').strip():
example = (txt.text or '').strip()
break
if example:
# Keep example on one line, clipped
snippet = example.replace('\n', ' ')
if len(snippet) > 160:
snippet = snippet[:157] + '...'
self.logger.info(f"- {name}: {rung_count} rungs | example: {snippet}", stage="summary")
else:
self.logger.info(f"- {name}: {rung_count} rungs", stage="summary")
def get_context_metadata(self) -> Dict[str, Any]:
"""Get metadata for routine context. Override to add custom metadata."""
@ -171,16 +212,8 @@ class SafetyProgramGenerator(BaseGenerator):
# Add safety tag map if needed
self._add_safety_tag_map()
# Add zones routine from configuration if available
try:
zones_df = self.data_loader.zones
if zones_df is not None:
from .routines.zones import create_zones_routine
create_zones_routine(self.builder.get_routines_section(), zones_df, self.data_loader.epc)
self.logger.info("Added R030_ZONES routine from zones.json")
except Exception:
# Zones are optional; proceed without blocking generation
pass
# Zones routine is now handled through routine_plan configuration
# No longer adding zones routine here to avoid duplication
# Ensure a MainRoutine exists and references generated safety routines
# The ProgramAttributes set MainRoutineName to config.routines.main_routine_name
@ -218,7 +251,7 @@ class SafetyProgramGenerator(BaseGenerator):
safety_tags = self.data_loader.safety_tags_from_pb
if safety_tags:
from .generators.safety_program import create_safety_tag_map
from .utils.safety_tag_map import create_safety_tag_map
create_safety_tag_map(program_element, safety_tags, set())
self.logger.debug(f"Added safety tag map with {len(safety_tags)} tags")

View File

@ -1,132 +0,0 @@
from __future__ import annotations
import argparse
from pathlib import Path
from generators import (
SafetyProgramGenerator,
MainProgramGenerator,
)
from writers import create_safety_tag_mapping
def _cmd_safety(args: argparse.Namespace) -> None:
"""Generate SafetyProgram L5X using safety-focused generator."""
gen = SafetyProgramGenerator(args.excel)
gen.write(args.output)
print(f"Safety L5X written to {args.output}")
def _cmd_main(args: argparse.Namespace) -> None:
"""Generate MainProgram L5X using safety-focused generator."""
gen = MainProgramGenerator(args.excel)
gen.write(args.output)
print(f"Main L5X written to {args.output}")
# CSV generation removed (deprecated)
def _cmd_mapping(args: argparse.Namespace) -> None:
cnt = create_safety_tag_mapping(args.excel, args.output)
print(f"Safety tag mapping ({cnt} entries) written to {args.output}")
def _cmd_safety_only(args: argparse.Namespace) -> None:
"""Generate only essential safety routines using DESC_IP data extraction (RST, STO, EPC)."""
# Check if ignore_estop1ok flag is set
ignore_estop1ok = getattr(args, 'ignore_estop1ok', False)
if ignore_estop1ok:
print("INFO: Ignoring ESTOP1OK tags in safety routines generation")
# Generate limited SafetyProgram with only 5 essential routines
safety_gen = SafetyProgramGenerator(args.excel, ignore_estop1ok=ignore_estop1ok)
safety_output = args.safety_output or 'SafetyProgram_Limited.L5X'
safety_gen.write(safety_output)
print(f"Limited Safety L5X written to {safety_output}")
# Generate limited MainProgram with only safety_tag_map and estop_check
main_gen = MainProgramGenerator(args.excel)
main_output = args.main_output or 'MainProgram_Limited.L5X'
main_gen.write(main_output)
print(f"Limited Main L5X written to {main_output}")
# CSV generation removed
# Create safety tag mapping for the limited mode
from data_loader import LimitedDataLoader
loader = LimitedDataLoader.from_excel(args.excel)
# Collect safety tags from RST sheet
safety_tags = set()
safety_tags.add("MCM_S_PB") # Static MCM tag
for _, row in loader.rst.iterrows():
if isinstance(row['DESCA'], str) and (any(k in row['DESCA'] for k in ('S1_PB', 'S2_PB')) or row['DESCA'].endswith('SPB')):
safety_tags.add(row['DESCA'])
mapping_output = args.mapping_output or 'SafetyTagMapping_Limited.txt'
from writers.mapping_writer import create_safety_tag_mapping
# For limited mode, we don't have beacon tags, so pass empty sets
create_safety_tag_mapping(safety_tags, set(), set(), mapping_output)
print(f"Limited safety tag mapping written to {mapping_output}")
print(f"\n[SUCCESS] Safety-only mode complete:")
print(f" - Safety routines: inputs, outputs, estops, resets")
print(f" - Main routines: safety_tag_map, estop_check")
print(f" - Data sources: DESC_IP extraction (RST, STO, EPC)")
_DEF_OUTPUTS = {
'safety': 'SafetyProgram_Generated.L5X',
'main': 'MainProgram_Generated.L5X',
'mapping': 'SafetyTagMapping.txt',
}
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(prog='aoi-generator', description='Generate safety-focused L5X artifacts from Excel spec.')
sub = p.add_subparsers(dest='cmd', required=True)
# Safety
s = sub.add_parser('safety', help='Generate SafetyProgram L5X')
s.add_argument('excel', help='Merged descriptor Excel file')
s.add_argument('-o', '--output', default=_DEF_OUTPUTS['safety'])
s.set_defaults(func=_cmd_safety)
# Main
m = sub.add_parser('main', help='Generate MainProgram L5X')
m.add_argument('excel')
m.add_argument('-o', '--output', default=_DEF_OUTPUTS['main'])
m.set_defaults(func=_cmd_main)
# CSV subcommand removed
# Mapping
mp = sub.add_parser('mapping', help='Generate SafetyTag mapping file')
mp.add_argument('excel')
mp.add_argument('-o', '--output', default=_DEF_OUTPUTS['mapping'])
mp.set_defaults(func=_cmd_mapping)
# Safety-only mode
so = sub.add_parser('safety-only', help='Generate only essential safety routines (inputs, outputs, estops, resets, safety_tag_map, estop_check) using DESC_IP data extraction')
so.add_argument('excel', help='Merged descriptor Excel file')
so.add_argument('--safety-output', help='Safety L5X output file (default: SafetyProgram_Limited.L5X)')
so.add_argument('--main-output', help='Main L5X output file (default: MainProgram_Limited.L5X)')
# CSV options removed
so.add_argument('--mapping-output', help='Safety tag mapping output file (default: SafetyTagMapping_Limited.txt)')
so.add_argument('--ignore-estop1ok', action='store_true', help='Ignore ESTOP1OK tags in inputs and estops routines')
so.set_defaults(func=_cmd_safety_only)
return p
def main(argv: list[str] | None = None) -> None:
parser = build_parser()
args = parser.parse_args(argv)
args.func(args)
if __name__ == '__main__':
main()

View File

@ -10,6 +10,7 @@ class FileConfig:
"""File path configuration."""
excel_file: Path = Path('DESC_IP_MERGED.xlsx')
output_dir: Path = Path('.')
zones_file: Path = Path('zones.json')
# Output file names
safety_l5x: str = 'SafetyProgram_Generated.L5X'
@ -126,6 +127,23 @@ class RoutineConfig:
# Safety tag mapping prefix and MCM input address
safety_tag_prefix: str = 'SFT_'
mcm_input_address: str = 'Local:5:I.Data.0'
# Global control and status tags
mcm_base_tag: str = 'MCM'
mcm_ctrl_tag: str = 'MCM.CTRL'
rack_fault_tag: str = 'Rack.AOI.Slot2_EN4TR_Faulted'
mcm_epb_status_tag: str = 'MCM_EPB_STATUS'
top_level_estop_ok_tag: str = 'EStop_MCM_OK'
station_ctrl_tag: str = 'Station.CTRL'
# MCM EPB wiring and tag names
mcm_epb_status_inputs: List[str] = field(default_factory=lambda: [
'Local:7:I.Pt02.Status',
'Local:7:I.Pt03.Status',
])
mcm_epb_dcs_inputs: List[str] = field(default_factory=lambda: [
'Local:7:I.Pt02.Data',
'Local:7:I.Pt03.Data',
])
mcm_epb_dcs_tag_name: str = 'MCM_EPB_DCS_CTRL'
# Safety routine names
inputs_routine: str = 'R010_INPUTS'
@ -138,6 +156,39 @@ class RoutineConfig:
mcm_safety_tag: str = 'MCM_S_PB'
mcm_epb_tag: str = 'MCM_EPB_DCS_CTRL.O1'
# Speed control and auxiliaries
speed_ctrl_setpoint_tag: str = 'Speed_350_FPM'
speed_ctrl_setpoint_value: int = 350
no_horn_tag_name: str = 'NO_Horn'
# AOI/APF defaults
apf_input_default: str = 'In_0'
# MCM AOI argument lists (after AOI, HMI, CTRL)
# Provide defaults matching current project wiring
mcm_aoi_input_args: List[str] = field(default_factory=lambda: [
'Local:5:I.Data.2',
'Local:5:I.Data.5',
'Local:5:I.Data.4',
'Local:5:I.Data.0',
'Local:5:I.Data.3',
'Local:7:I.Pt02.Data',
'Local:7:I.Pt03.Data',
'Local:5:I.Data.1',
'Local:7:I.Pt00.Data',
'Local:5:I.Data.7',
'Local:5:I.Data.8',
'Local:5:I.Data.6',
'Local:5:I.Data.9',
])
mcm_aoi_output_args: List[str] = field(default_factory=lambda: [
'Local:6:O.Data.2',
'Local:6:O.Data.5',
'Local:6:O.Data.4',
'Local:6:O.Data.0',
'Local:6:O.Data.1',
'Local:6:O.Data.3',
])
# Routine name map for all known plugins (can be overridden in config)
name_map: Dict[str, str] = field(default_factory=lambda: {
'main_routine': 'MainRoutine',
@ -227,6 +278,8 @@ class GeneratorConfig:
files_data['excel_file'] = Path(files_data['excel_file'])
if 'output_dir' in files_data:
files_data['output_dir'] = Path(files_data['output_dir'])
if 'zones_file' in files_data and files_data['zones_file']:
files_data['zones_file'] = Path(files_data['zones_file'])
files = FileConfig(**files_data)
xml = XMLConfig(**config_data.get('xml', {}))
@ -237,16 +290,22 @@ class GeneratorConfig:
routine_plan: List[RoutineEntry] = []
routines: RoutineConfig
if isinstance(routines_section, list):
# New plan format under key 'routines'
# Legacy: plan mistakenly stored under 'routines' key
for entry in routines_section:
try:
routine_plan.append(RoutineEntry(**entry))
except Exception:
# Skip invalid entries silently to keep robustness
continue
routines = RoutineConfig()
else:
routines = RoutineConfig(**routines_section)
# Prefer explicit routine_plan key when present
if not routine_plan and isinstance(config_data.get('routine_plan', None), list):
for entry in config_data['routine_plan']:
try:
routine_plan.append(RoutineEntry(**entry))
except Exception:
continue
# Optional filters section
filters_section = config_data.get('filters', {})
@ -271,6 +330,7 @@ class GeneratorConfig:
'xml': self.xml.__dict__,
'extraction': self.extraction.__dict__,
'routines': self.routines.__dict__,
'routine_plan': [e.__dict__ for e in self.routine_plan],
'tags': self.tags,
}
# Intentionally do not overwrite user's list-based routines if present; save only legacy schema by default.

View File

@ -6,6 +6,7 @@ from typing import Optional, List, Dict, Any
import pandas as pd
import re
from .utils.common import natural_sort_key
from .logging_config import get_logger
@dataclass
class DataLoader:
@ -14,8 +15,8 @@ class DataLoader:
Removes the complexity of dual-mode operation since sheet-based
mode is deprecated and will never be used.
Zones configuration is provided via zones_dict parameter or
defaults to zones_config.py. No longer reads ZONES sheet from Excel.
Zones configuration is provided via `files.zones_file` (zones.json) in
generator_config.json. ZONES sheet in Excel is ignored and not used.
Supported Excel sheets: DESC_IP only
External files: IO-To-Path.xlsx (for IO path mappings)
@ -35,6 +36,7 @@ class DataLoader:
self.excel_path = Path(self.excel_path)
self._extracted_data = {}
self._cache = {}
self._logger = get_logger(self.__class__.__name__)
# Zones deprecated: ensure zones_dict is an empty list
self.zones_dict = []
@ -60,10 +62,10 @@ class DataLoader:
@property
def network(self) -> pd.DataFrame:
"""Get NETWORK sheet data."""
"""Get NETWORK_PLC sheet data."""
if 'network' not in self._cache:
try:
df = pd.read_excel(self.excel_path, sheet_name='NETWORK')
df = pd.read_excel(self.excel_path, sheet_name='NETWORK_PLC')
# Coerce commonly used text columns to string to allow safe .str usage
for col in ['Name', 'PartNumber', 'DPM']:
if col in df.columns:
@ -117,28 +119,35 @@ class DataLoader:
@property
def zones(self) -> pd.DataFrame:
"""Load zones from zones.json configuration.
"""Load zones from configurable JSON (files.zones_file in config).
The JSON file is expected at project root as `zones.json` with a
top-level object keyed by subsystem (e.g., MCM01, MCM04) and a
`DEFAULT` fallback. Each entry is a list of objects having
fields: name, start, stop, interlock.
The JSON should contain a top-level object keyed by subsystem
(e.g., MCM01, MCM04) with a `DEFAULT` fallback. Each entry is a list
of objects with fields: name, start, stop, interlock.
"""
if 'zones' in self._cache:
return self._cache['zones']
import json
import os
# Determine subsystem from Excel path
import re
excel_path_str = str(self.excel_path)
m = re.search(r"(MCM\d+)", excel_path_str, re.IGNORECASE)
subsystem = (m.group(1).upper() if m else 'DEFAULT')
json_path = Path(__file__).parent.parent.parent / 'zones copy.json'
# Resolve zones file from config
try:
from .config import get_config
cfg = get_config()
zones_file = cfg.files.zones_file
except Exception:
zones_file = Path('zones.json')
# Make path relative to project root if needed
if not zones_file.is_absolute():
zones_file = Path(__file__).parent.parent.parent / zones_file
zones_df = pd.DataFrame(columns=['name', 'start', 'stop', 'interlock'])
try:
with open(json_path, 'r', encoding='utf-8') as f:
with open(zones_file, 'r', encoding='utf-8') as f:
data = json.load(f)
# Pick group: prefer explicit subsystem; otherwise, choose the best
@ -390,12 +399,12 @@ class DataLoader:
@property
def apf(self) -> pd.DataFrame:
"""Get APF data from NETWORK sheet."""
"""Get APF data from NETWORK_PLC sheet."""
return self._extract_apf()
def _extract_apf(self) -> pd.DataFrame:
"""Extract APF (Variable Frequency Drive) data from NETWORK sheet."""
# Use centralized NETWORK accessor which normalizes dtypes
"""Extract APF (Variable Frequency Drive) data from NETWORK_PLC sheet."""
# Use centralized NETWORK_PLC accessor which normalizes dtypes
network_df = self.network
if network_df.empty:
return pd.DataFrame()
@ -426,12 +435,12 @@ class DataLoader:
@property
def extendo(self) -> pd.DataFrame:
"""Get EXTENDO data from NETWORK sheet."""
"""Get EXTENDO data from NETWORK_PLC sheet."""
return self._extract_extendo()
def _extract_extendo(self) -> pd.DataFrame:
"""Extract EXTENDO (Siemens ET 200SP) data from NETWORK sheet."""
# Use centralized NETWORK accessor which normalizes dtypes
"""Extract EXTENDO (Siemens ET 200SP) data from NETWORK_PLC sheet."""
# Use centralized NETWORK_PLC accessor which normalizes dtypes
network_df = self.network
if network_df.empty:
return pd.DataFrame()
@ -504,7 +513,7 @@ class DataLoader:
return fpe_data
def _extract_d2c_data(self) -> dict:
"""Extract D2C data from DESC_IP and NETWORK sheets."""
"""Extract D2C data from DESC_IP and NETWORK_PLC sheets."""
import re
# Get config tokens
cfg = None
@ -519,7 +528,7 @@ class DataLoader:
bcn_token = (getattr(cfg.extraction, 'd2c_bcn_token', None) if cfg else None) or 'BCN'
zmx_suffix = (getattr(cfg.extraction, 'd2c_zmx_suffix', None) if cfg else None) or '_ZMX'
# Get DESC_IP and NETWORK dataframes
# Get DESC_IP and NETWORK_PLC dataframes
desc_ip_df = self.desc_ip
network_df = self.network
if desc_ip_df.empty or network_df.empty:
@ -556,7 +565,7 @@ class DataLoader:
stack_type = '3 STACK' if '3 STACK' in desca_upper or '3-STACK' in desca_upper else '2 STACK'
bcn_name = bcn_row['DESCA'].split()[0] if pd.notna(bcn_row.get('DESCA')) else f"{s0}_{bcn_token}1"
s0_data[s0]['bcn'] = { 'tagname': bcn_name, 'stack_type': stack_type }
# ZMX in NETWORK
# ZMX in NETWORK_PLC
zmx = network_df[network_df['Name'].astype(str).str.contains(f'{re.escape(s0)}{re.escape(zmx_suffix)}', na=False, regex=True)]
if not zmx.empty:
zmx_row = zmx.iloc[0]
@ -844,7 +853,7 @@ class DataLoader:
def _extract_fpe_data(self) -> Dict[str, Dict[str, str]]:
"""Extract FPE (Full Photo Eye) data."""
print("\n [DataLoader] Extracting FPE data...")
self._logger.debug("Extracting FPE data", stage="data_extraction", type="FPE")
desc_ip = self.desc_ip
network = self.network
@ -862,10 +871,10 @@ class DataLoader:
fpe_entries = desc_ip[fpe_mask]
if fpe_entries.empty:
print(" No FPE entries found")
self._logger.info("Data: FPE count=0")
return {}
print(f" Found {len(fpe_entries)} FPE entries")
self._logger.info(f"Data: FPE count={len(fpe_entries)}")
fpe_data = {}
@ -897,7 +906,7 @@ class DataLoader:
print(f" [WARNING] Could not extract base name from {fpe_name}")
continue
print(f"\n Processing {fpe_name} (base: {base_name})")
self._logger.debug(f"FPE processing {fpe_name} base={base_name}")
# Find associated VFD from network sheet
vfd_name = f"{base_name}_VFD1"
@ -911,7 +920,7 @@ class DataLoader:
if not vfd_row.empty:
conveyor_ctrl = f"{vfd_name}.CTRL"
else:
print(f" [WARNING] No VFD found for {base_name}")
self._logger.debug(f"No VFD found for {base_name}")
vfd_name = f"{base_name}_VFD1" # Use default VFD name
conveyor_ctrl = f"{vfd_name}.CTRL"
@ -967,12 +976,12 @@ class DataLoader:
'beacon_output': beacon_output
}
print(f" Conveyor: {conveyor_ctrl}")
print(f" Parent Fault: {parent_comm_fault}")
print(f" Input Path: {input_path}")
print(f" Beacon Output: {beacon_output}")
# Detailed per-device values logged at DEBUG to reduce noise
self._logger.debug(
f"FPE {fpe_name}: conveyor={conveyor_ctrl} parent_fault={parent_comm_fault} input={input_path} beacon={beacon_output}"
)
print(f"\n Extracted {len(fpe_data)} FPE configurations")
self._logger.info(f"Data: FPE configs={len(fpe_data)}")
return fpe_data
@property
@ -986,12 +995,12 @@ class DataLoader:
return pmm_data
def _extract_pmm_data(self) -> Dict[str, Dict[str, Any]]:
"""Extract PMM data from NETWORK and DESC sheets."""
"""Extract PMM data from NETWORK_PLC and DESC sheets."""
pmm_data = {}
print("\n=== Extracting PMM Data ===")
self._logger.debug("Extracting PMM data", stage="data_extraction", type="PMM")
# Get PMM entries from NETWORK sheet (part number 1420-V2-ENT)
# Get PMM entries from NETWORK_PLC sheet (part number 1420-V2-ENT)
network = self.network
desc_ip = self.desc_ip
@ -1005,15 +1014,15 @@ class DataLoader:
target = (getattr(cfg.extraction, 'pmm_partnumber_exact', None) if cfg else None) or ['1420-V2-ENT']
pmm_entries = network[network['PartNumber'].isin(target)]
print(f"Found {len(pmm_entries)} PMM entries")
self._logger.info(f"Data: PMM entries={len(pmm_entries)}")
for _, pmm in pmm_entries.iterrows():
pmm_name = pmm['Name']
print(f"\n Processing PMM: {pmm_name}")
self._logger.debug(f"PMM processing {pmm_name}")
# Get DPM association
dpm_name = pmm.get('DPM', 'MCM')
print(f" DPM: {dpm_name}")
self._logger.debug(f"PMM {pmm_name} DPM={dpm_name}")
# Find PWM (Phase/Power Monitor) fault input
# Extract base name (e.g., PDP11 from PDP11_PMM1)
@ -1030,7 +1039,7 @@ class DataLoader:
io_path = pwm_row.get('IO_PATH', '')
if io_path:
pwm_fault_io = io_path
print(f" PWM Fault IO: {pwm_fault_io}")
self._logger.debug(f"PMM {pmm_name} PWM fault IO {pwm_fault_io}")
else:
# Build from TAGNAME and TERM
tagname = pwm_row['TAGNAME']
@ -1039,7 +1048,7 @@ class DataLoader:
# Convert term format (IO12 -> Pt12)
pt_num = term.replace('IO', 'Pt')
pwm_fault_io = f"{tagname}:I.{pt_num}.Data"
print(f" PWM Fault IO (constructed): {pwm_fault_io}")
self._logger.debug(f"PMM {pmm_name} PWM fault IO (constructed) {pwm_fault_io}")
# Store PMM configuration
pmm_data[pmm_name] = {
@ -1048,9 +1057,9 @@ class DataLoader:
'parent_comm_fault': f"{dpm_name}:I.ConnectionFaulted"
}
print(f" Configuration stored for {pmm_name}")
self._logger.debug(f"PMM {pmm_name} configuration stored")
print(f"\n Extracted {len(pmm_data)} PMM configurations")
self._logger.info(f"Data: PMM configs={len(pmm_data)}")
return pmm_data
@property
@ -1067,7 +1076,7 @@ class DataLoader:
"""Extract CB_MONITOR data from DESC sheets."""
cb_monitor_data = {}
print("\n=== Extracting CB_MONITOR Data ===")
self._logger.debug("Extracting CB_MONITOR data", stage="data_extraction", type="CB_MONITOR")
desc_ip = self.desc_ip
@ -1135,14 +1144,14 @@ class DataLoader:
if pd.notna(cb['TAGNAME']):
pdp_fios[pdp_base].add(cb['TAGNAME'])
print(f"Found CB entries for {len(pdp_cbs)} PDPs")
self._logger.info(f"Data: CB PDPs={len(pdp_cbs)}")
# Now create the CB_MONITOR configurations
for pdp_base in sorted(pdp_cbs.keys()):
cb_ios = pdp_cbs[pdp_base]
fios = pdp_fios[pdp_base]
print(f"\n Processing {pdp_base} with {len(cb_ios)} CBs from {len(fios)} FIO(s)")
self._logger.debug(f"CB_MONITOR {pdp_base}: CBs={len(cb_ios)} FIOs={len(fios)}")
# Create ordered list of CB IO paths (CB1 through CB26)
cb_list = []
@ -1166,11 +1175,11 @@ class DataLoader:
'connection_fault': connection_fault
}
print(f" Configured {pdp_base} with {len([cb for cb in cb_list if cb != '0'])} CBs")
print(f" CB positions: {sorted([i for i in cb_ios.keys()])}")
print(f" Connection fault: {connection_fault}")
self._logger.debug(
f"CB_MONITOR {pdp_base}: configured CBs={len([cb for cb in cb_list if cb != '0'])} positions={sorted([i for i in cb_ios.keys()])} fault={connection_fault}"
)
print(f"\n Extracted {len(cb_monitor_data)} CB_MONITOR configurations")
self._logger.info(f"Data: CB configs={len(cb_monitor_data)}")
return cb_monitor_data
@property
@ -1184,10 +1193,10 @@ class DataLoader:
return flow_ctrl_data
def _extract_flow_ctrl_data(self) -> Dict[str, Dict[str, Any]]:
"""Extract FLOW_CTRL data from NETWORK sheet."""
"""Extract FLOW_CTRL data from NETWORK_PLC sheet."""
flow_ctrl_data = {}
print("\n=== Extracting FLOW_CTRL Data ===")
self._logger.debug("Extracting FLOW_CTRL data", stage="data_extraction", type="FLOW_CTRL")
network = self.network
@ -1203,8 +1212,7 @@ class DataLoader:
extendo_entries = network[name_series.str.endswith('_EX1', na=False)]
vfd_entries = network[name_series.str.endswith('_VFD1', na=False)]
print(f"Found {len(extendo_entries)} EXTENDO devices")
print(f"Found {len(vfd_entries)} VFD devices")
self._logger.info(f"Data: EXTENDO={len(extendo_entries)} VFD={len(vfd_entries)}")
# Group by union of DPMs from EXTENDO and VFD so lanes without EXTENDO aren't dropped
dpm_keys = sorted(set(extendo_entries['DPM'].dropna().unique()).union(set(vfd_entries['DPM'].dropna().unique())))
@ -1212,9 +1220,7 @@ class DataLoader:
dpm_extendos = extendo_entries[extendo_entries['DPM'] == dpm] if 'DPM' in extendo_entries.columns else extendo_entries.iloc[0:0]
dpm_vfds = vfd_entries[vfd_entries['DPM'] == dpm] if 'DPM' in vfd_entries.columns else vfd_entries.iloc[0:0]
print(f"\n Processing DPM: {dpm}")
print(f" EXTENDOs: {len(dpm_extendos)}")
print(f" VFDs: {len(dpm_vfds)}")
self._logger.debug(f"FLOW_CTRL DPM={dpm} extendos={len(dpm_extendos)} vfds={len(dpm_vfds)}")
# Create a list of devices for this DPM
devices = []
@ -1258,7 +1264,7 @@ class DataLoader:
'devices': devices
}
print(f"\n Extracted FLOW_CTRL configurations for {len(flow_ctrl_data)} DPMs")
self._logger.info(f"Data: FLOW_CTRL DPMs={len(flow_ctrl_data)}")
return flow_ctrl_data
@property
@ -1272,10 +1278,10 @@ class DataLoader:
return speed_ctrl_data
def _extract_speed_ctrl_data(self) -> List[str]:
"""Extract VFD names for SPEED_CTRL from NETWORK sheet."""
"""Extract VFD names for SPEED_CTRL from NETWORK_PLC sheet."""
vfd_names = []
print("\n=== Extracting SPEED_CTRL Data ===")
self._logger.debug("Extracting SPEED_CTRL data", stage="data_extraction", type="SPEED_CTRL")
network = self.network
@ -1292,7 +1298,7 @@ class DataLoader:
vfd_mask = vfd_mask | network['PartNumber'].str.startswith(p, na=False)
vfd_entries = network[vfd_mask]
print(f"Found {len(vfd_entries)} VFD devices for speed control")
self._logger.info(f"Data: SPEED_CTRL VFDs={len(vfd_entries)}")
# Extract VFD names
for _, vfd in vfd_entries.iterrows():
@ -1302,8 +1308,8 @@ class DataLoader:
# Sort for consistent output
vfd_names.sort(key=natural_sort_key)
print(f" VFDs: {', '.join(vfd_names[:5])}..." if len(vfd_names) > 5 else f" VFDs: {', '.join(vfd_names)}")
print(f"\n Extracted {len(vfd_names)} VFDs for SPEED_CTRL")
self._logger.debug("SPEED_CTRL sample=" + (', '.join(vfd_names[:5]) + ('...' if len(vfd_names) > 5 else '')))
self._logger.info(f"Data: SPEED_CTRL count={len(vfd_names)}")
return vfd_names
@classmethod

Some files were not shown because too many files have changed in this diff Show More