115 lines
4.9 KiB
Python

"""Example MainRoutine plugin to demonstrate the plugin architecture."""
import xml.etree.ElementTree as ET
from typing import List
from ..plugin_system import RoutinePlugin
class MainRoutinePlugin(RoutinePlugin):
"""Plugin for generating the MainRoutine."""
# Plugin metadata
name = "main_routine"
description = "Generates the main program routine with JSR calls"
version = "1.0.0"
category = "core"
dependencies = []
def can_generate(self) -> bool:
"""Check if we can generate the main routine."""
# Main routine can always be generated
return True
def validate_data(self) -> List[str]:
"""Validate required data."""
errors = []
# Check if routines element exists
if self.context.routines_element is None:
errors.append("Routines element is required")
return errors
def generate(self) -> bool:
"""Generate the MainRoutine with JSR calls to created routines."""
try:
self.logger.info("Generating MainRoutine with JSR calls")
# Resolve routine names from config mapping
try:
nm = self.context.config.routines.name_map
except Exception:
nm = {}
# If a routine plan is present, honor its order for MainProgram
calls: List[str] = []
try:
plan = getattr(self.context.config, 'routine_plan', []) or []
ordered = [e for e in plan if getattr(e, 'enabled', True) and getattr(e, 'program', 'MainProgram') == 'MainProgram']
ordered.sort(key=lambda e: getattr(e, 'order', 100))
for entry in ordered:
# Skip generating a JSR to ourselves
if getattr(entry, 'plugin', '') == 'main_routine' or getattr(entry, 'name', '') == 'main_routine':
continue
# Map plugin/name to configured routine name
plugin_key = getattr(entry, 'plugin', '') or getattr(entry, 'name', '')
routine_name = nm.get(plugin_key, nm.get(getattr(entry, 'name', ''), getattr(entry, 'name', '')))
if routine_name:
calls.append(routine_name)
except Exception:
calls = []
# Fallback to comprehensive default order if no plan provided
if not calls:
defaults = [
nm.get('safety_tag_map', 'R130_SAFETY_TAG_MAP'),
nm.get('rack', 'R011_RACK'),
nm.get('mcm', 'R010_MCM'),
nm.get('dpm', 'R020_DPM'),
nm.get('fiom', 'R030_FIOM'),
nm.get('fioh', 'R031_FIOH'),
nm.get('apf', 'R040_APF'),
nm.get('extendo', 'R041_EXTENDO'),
nm.get('flow_ctrl', 'R050_FLOW_CTRL'),
nm.get('speed_ctrl', 'R051_SPEED_CTRL'),
nm.get('d2c_chute', 'R042_D2C_CHUTE'),
nm.get('pb_chute', 'R043_PB_CHUTE'),
nm.get('station_jr_chute', 'R044_STATION_JR_CHUTE'),
nm.get('pmm', 'R060_PMM'),
nm.get('cb_monitor', 'R070_CB_MONITOR'),
nm.get('station_jr_pb', 'R090_STATION_JR_PB'),
nm.get('jpe', 'R100_JPE'),
nm.get('fpe', 'R101_FPE'),
nm.get('estop_check', 'R120_ESTOP_CHECK'),
]
calls = [c for c in defaults if c]
# Filter to only include JSRs for routines that actually exist in the program
existing = {r.get('Name') for r in self.context.routines_element.findall('Routine')}
calls = [c for c in calls if c in existing]
# Create the MainRoutine
routine = ET.SubElement(self.context.routines_element, "Routine")
routine.set("Name", self.context.config.routines.main_routine_name if hasattr(self.context.config, 'routines') else "MainRoutine")
routine.set("Type", "RLL")
# Create RLL content
rll_content = ET.SubElement(routine, "RLLContent")
# Single rung with JSR calls in the configured order
rung = ET.SubElement(rll_content, "Rung")
rung.set("Number", "0")
rung.set("Type", "N")
text = ET.SubElement(rung, "Text")
if calls:
text.text = '[' + ' ,'.join(f'JSR({c},0)' for c in calls) + ' ];'
else:
text.text = 'NOP();'
self.logger.info("Successfully generated MainRoutine")
return True
except Exception as e:
self.logger.error(f"Failed to generate MainRoutine: {e}")
return False