557 lines
20 KiB
Python
557 lines
20 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Absichtlich ohne Shebang: der Windows-py-Launcher wuerde daraus "python3"
|
|
# ableiten und scheitert, wenn keine PythonCore-Installation registriert ist.
|
|
"""
|
|
tro_catalog.py - Typdefinition der TROs (Transfer Route Objects).
|
|
|
|
Dieses Modul ist die **einzige** Quelle fuer alles, was zur Erzeugung eines TRO
|
|
gebraucht wird. Es liest keine Dateien und braucht kein Markdown zur Laufzeit -
|
|
die Herkunft der Daten steht nur noch in den Kommentaren.
|
|
|
|
Ein TRO-Typ wird durch fuenf Dinge beschrieben:
|
|
|
|
1. Name - Kurztyp, wie in FB_Main und connect.ini verwendet ("1Sep")
|
|
2. FB-Baustein - der Siemens-Funktionsbaustein ("FB_ILS_MTRO_1Sep")
|
|
3. Bauteile - welche Elemente in diesem TRO stecken und wie viele
|
|
(1Sep = 1x Separator, 1Sep1Swi = 1x Separator + 1x Weiche)
|
|
4. Farbe - Farbgruppe fuer Zeichnungen (Graphviz, Mermaid, CAD)
|
|
5. Symbol - Form des CAD-Markers, je Typ eine eigene (Kreis, Dreieck,
|
|
Rechteck, Raute ...)
|
|
|
|
Herkunft der Daten (Stand :data:`CATALOG_AS_OF`)
|
|
-----------------------------------------------
|
|
Einmalig uebernommen aus - danach hier gepflegt, nicht mehr nachgelesen:
|
|
|
|
doc/TRO_Katalog/TRO_Katalog.md
|
|
"Overview of all TRO types" -> Typname und FB-Baustein
|
|
"Color legend" -> Farbgruppen (siehe TroStyle)
|
|
doc/TRO_Typen.md
|
|
"Baukasten-Analyse" -> Bauteile je Typ (Sub-Bausteine/STRO)
|
|
doc/HundM/Json_Layout-Konzept.md
|
|
classDef-Farben -> die konkreten Farbwerte
|
|
doc/TRO_Katalog/scl_templates/*.scl
|
|
VAR-Deklarationen der lokal vorliegenden FBs - dort sind die Bauteile
|
|
direkt nachweisbar
|
|
|
|
Belegbarkeit der Bauteillisten
|
|
------------------------------
|
|
Nur vier FBs liegen als Quelle im Repo; deren Bauteile sind aus den
|
|
VAR-Deklarationen **verifiziert** (Kommentar "aus SCL belegt"). Die uebrigen
|
|
Typen sind `.liblink`-Referenzen auf die externe ILSLib - ihre Bauteile stammen
|
|
aus der Mapping-Tabelle in TRO_Typen.md (Kommentar "laut TRO_Typen.md").
|
|
|
|
Verwendung
|
|
----------
|
|
from tro_catalog import TroItem, get_tro, tro_names
|
|
|
|
tro = get_tro("1Sep1Swi")
|
|
tro.get_fb_block() -> "FB_ILS_MTRO_1Sep1Swi"
|
|
tro.get_item_count(TroItem.SWITCH) -> 1
|
|
tro.get_items() -> {"Separator": 1, "Switch": 1}
|
|
tro.describe_items() -> "1x Separator, 1x Switch"
|
|
tro.get_style().fill -> "#ffe4a0"
|
|
tro.get_dot_attrs() -> {"fillcolor": ..., "color": ...}
|
|
tro.set_item(TroItem.SCANNER, 1) -> Bauteil ergaenzen/aendern
|
|
|
|
TroDefinition ist ein Pydantic-Modell (v2). Neben den get_*/set_*-Methoden gibt
|
|
es damit Validierung bei jeder Zuweisung sowie model_dump()/model_dump_json()
|
|
und model_validate() fuer das geplante JSON-Layoutmodell.
|
|
Benoetigt `pydantic >= 2.0.0` (siehe requirements.txt, bin/install_py).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
|
|
__all__ = [
|
|
"CATALOG_AS_OF",
|
|
"TroItem",
|
|
"TroStyle",
|
|
"TroSymbol",
|
|
"TroDefinition",
|
|
"ITEM_FB",
|
|
"STYLES",
|
|
"TRO_CATALOG",
|
|
"get_tro",
|
|
"tro_names",
|
|
"set_tro",
|
|
"catalog",
|
|
"mermaid_classdefs",
|
|
]
|
|
|
|
# Stand der Dokumente, aus denen die Typdefinition uebernommen wurde
|
|
CATALOG_AS_OF = "2026-07-20"
|
|
|
|
|
|
class TroItem:
|
|
"""
|
|
Bauteilarten, aus denen ein TRO zusammengesetzt ist.
|
|
|
|
Konstanten statt freier Strings, damit Tippfehler auffallen.
|
|
:data:`ITEM_FB` ordnet jeder Art ihren Sub-Funktionsbaustein zu.
|
|
"""
|
|
|
|
SEPARATOR = "Separator"
|
|
SWITCH = "Switch"
|
|
SCANNER = "Scanner"
|
|
VARIO_DRIVE = "VarioDrive"
|
|
WORK_STATION = "WorkStation"
|
|
STORAGE_LINE = "StorageLine"
|
|
ACCUMULATE = "Accumulate"
|
|
ENCODER = "Encoder"
|
|
SSCC = "SSCC"
|
|
BOOM = "Boom"
|
|
FOOT = "Foot"
|
|
TILT_SENSOR = "TiltSensor"
|
|
|
|
@classmethod
|
|
def all(cls) -> tuple[str, ...]:
|
|
"""Alle bekannten Bauteilarten."""
|
|
return tuple(
|
|
value
|
|
for key, value in vars(cls).items()
|
|
if key.isupper() and isinstance(value, str)
|
|
)
|
|
|
|
|
|
# Sub-Funktionsbaustein je Bauteilart. Leer = kein eigener FB (Hardware bzw.
|
|
# im Rahmenwerk des TRO umgesetzt).
|
|
ITEM_FB: dict[str, str] = {
|
|
TroItem.SEPARATOR: "FB_ILS_STRO_Sep",
|
|
TroItem.SWITCH: "FB_ILS_STRO_Switch",
|
|
TroItem.SCANNER: "FB_BarcodeReaderCognex",
|
|
TroItem.VARIO_DRIVE: "FB_ILS_STRO_Vario",
|
|
TroItem.WORK_STATION: "FB_ILS_STRO_Vario_WorkStation",
|
|
TroItem.STORAGE_LINE: "FB_ILS_STRO_Sep", # als Array[1..N]
|
|
TroItem.ACCUMULATE: "FB_CarrAccumulate1Sep",
|
|
TroItem.ENCODER: "",
|
|
TroItem.SSCC: "",
|
|
TroItem.BOOM: "FB_BoomWorkStation",
|
|
TroItem.FOOT: "FB_DistanceFoot",
|
|
TroItem.TILT_SENSOR: "FB_Tilt_TEST",
|
|
}
|
|
|
|
|
|
class TroSymbol:
|
|
"""
|
|
Zeichensymbole fuer die Marker in der Zeichnung.
|
|
|
|
Die Farbe gruppiert (siehe TroStyle), das Symbol unterscheidet den einzelnen
|
|
Typ. Alle TROs eines Typs bekommen dasselbe Symbol. Die Formen sind absichtlich
|
|
einfach - Kreis, Vielecke, Rechteck - damit sie in jedem Zoom erkennbar
|
|
bleiben und als LWPOLYLINE bzw. CIRCLE in den Block passen.
|
|
"""
|
|
|
|
CIRCLE = "circle" # Kreis
|
|
DOUBLE_CIRCLE = "double_circle" # Kreis mit zweitem Kreis innen
|
|
TRIANGLE = "triangle" # Dreieck, Spitze oben
|
|
TRIANGLE_DOWN = "triangle_down" # Dreieck, Spitze unten
|
|
SQUARE = "square" # Quadrat
|
|
DIAMOND = "diamond" # Raute
|
|
PENTAGON = "pentagon" # Fuenfeck
|
|
HEXAGON = "hexagon" # Sechseck
|
|
RECT = "rect" # liegendes Rechteck
|
|
ARROW = "arrow" # Pfeil/Fahne
|
|
# Dreieck mit zweitem Dreieck innen - fuer 2Sep2Swi, sichtbar verwandt mit
|
|
# TRIANGLE_DOWN (2Sep1Swi) und trotzdem davon unterscheidbar.
|
|
DOUBLE_TRIANGLE_DOWN = "double_triangle_down"
|
|
|
|
@classmethod
|
|
def all(cls) -> tuple[str, ...]:
|
|
return tuple(
|
|
value
|
|
for key, value in vars(cls).items()
|
|
if key.isupper() and isinstance(value, str)
|
|
)
|
|
|
|
|
|
class TroStyle(BaseModel):
|
|
"""
|
|
Darstellung einer TRO-Typgruppe.
|
|
|
|
Farbwerte uebernommen aus der "Color legend" in TRO_Katalog.md bzw. den
|
|
classDef-Zeilen in Json_Layout-Konzept.md:
|
|
|
|
sep blau Separator (1Sep)
|
|
swi orange Weiche (1Sep1Swi, 1Sep2Swi, 2Sep1Swi)
|
|
sscc rot Scanner-Sonderfall (1Sep_SSCC)
|
|
vario violett Kettenfoerderer (Vario, Vario_workStation)
|
|
store gruen Speicher/Puffer (PinStore_Auto, EmptyCarrBuffer)
|
|
ext grau Systemgrenze, extern, Loading Boom
|
|
|
|
Wichtig: gruen bedeutet **Speicher**, nicht Foerderer. Der Vario ist
|
|
violett.
|
|
"""
|
|
|
|
model_config = ConfigDict(validate_assignment=True, extra="forbid",
|
|
str_strip_whitespace=True)
|
|
|
|
group: str = Field(min_length=1, description="Kurzname der Farbgruppe, z. B. 'vario'")
|
|
label: str = Field(min_length=1, description="Klartext, z. B. 'Kettenfoerderer'")
|
|
fill: str = Field(min_length=4, description="Fuellfarbe als Hex, z. B. '#e8d4f0'")
|
|
stroke: str = Field(min_length=4, description="Randfarbe als Hex")
|
|
font: str = Field(default="#111111", min_length=4, description="Schriftfarbe")
|
|
|
|
def get_group(self) -> str:
|
|
return self.group
|
|
|
|
def get_fill(self) -> str:
|
|
return self.fill
|
|
|
|
def get_stroke(self) -> str:
|
|
return self.stroke
|
|
|
|
def get_font(self) -> str:
|
|
return self.font
|
|
|
|
def dot_attrs(self) -> dict[str, str]:
|
|
"""Graphviz-Knotenattribute."""
|
|
return {"fillcolor": self.fill, "color": self.stroke, "fontcolor": self.font}
|
|
|
|
def mermaid_classdef(self) -> str:
|
|
"""Mermaid-classDef-Zeile fuer diese Gruppe."""
|
|
return (
|
|
f"classDef {self.group} fill:{self.fill},"
|
|
f"stroke:{self.stroke},color:{self.font}"
|
|
)
|
|
|
|
|
|
# Farbgruppen - eine Instanz je Gruppe, von den Typen unten referenziert.
|
|
STYLE_SEP = TroStyle(group="sep", label="Separator",
|
|
fill="#d4e8ff", stroke="#3388cc")
|
|
STYLE_SWI = TroStyle(group="swi", label="Weiche",
|
|
fill="#ffe4a0", stroke="#cc8800")
|
|
STYLE_SSCC = TroStyle(group="sscc", label="Scanner (SSCC)",
|
|
fill="#ffd4d4", stroke="#cc3333")
|
|
STYLE_VARIO = TroStyle(group="vario", label="Kettenfoerderer",
|
|
fill="#e8d4f0", stroke="#883388")
|
|
STYLE_STORE = TroStyle(group="store", label="Speicher / Puffer",
|
|
fill="#d4f0d4", stroke="#338833")
|
|
STYLE_EXT = TroStyle(group="ext", label="Systemgrenze / extern",
|
|
fill="#f0f0f0", stroke="#888888", font="#404040")
|
|
|
|
STYLES: tuple[TroStyle, ...] = (
|
|
STYLE_SEP, STYLE_SWI, STYLE_SSCC, STYLE_VARIO, STYLE_STORE, STYLE_EXT,
|
|
)
|
|
|
|
|
|
class TroDefinition(BaseModel):
|
|
"""
|
|
Ein TRO-Typ: Name, FB-Baustein, Bauteile und Darstellung.
|
|
|
|
Pydantic-Modell - die Felder werden bei Erzeugung *und* bei jeder Zuweisung
|
|
geprueft (`validate_assignment`). Damit ist ein TroDefinition-Objekt nie in
|
|
einem ungueltigen Zustand:
|
|
|
|
name nicht leer
|
|
fb_block nicht leer
|
|
items {Bauteilart: Anzahl}, Anzahl >= 1, Art nicht leer;
|
|
Eintraege mit Anzahl <= 0 werden verworfen
|
|
|
|
Positionsargumente sind weiter moeglich (`TroDefinition("1Sep", "FB_...")`),
|
|
ebenso benannte (`TroDefinition(name="1Sep", fb_block="FB_...")`).
|
|
|
|
Weil es ein BaseModel ist, gibt es Serialisierung gratis - nuetzlich fuer
|
|
das geplante JSON-Layoutmodell:
|
|
|
|
tro.model_dump() -> dict
|
|
tro.model_dump_json(indent=2) -> JSON
|
|
TroDefinition.model_validate(d) -> aus dict
|
|
TroDefinition.model_json_schema() -> JSON-Schema
|
|
"""
|
|
|
|
model_config = ConfigDict(
|
|
validate_assignment=True, # set_* darf nichts Ungueltiges hinterlassen
|
|
extra="forbid", # Tippfehler in Feldnamen fallen auf
|
|
str_strip_whitespace=True,
|
|
)
|
|
|
|
name: str = Field(
|
|
min_length=1,
|
|
description="Kurztyp, wie in FB_Main und connect.ini verwendet, z. B. '1Sep'",
|
|
)
|
|
fb_block: str = Field(
|
|
min_length=1,
|
|
description="Name des Siemens-Funktionsbausteins, z. B. 'FB_ILS_MTRO_1Sep'",
|
|
)
|
|
items: dict[str, int] = Field(
|
|
default_factory=dict,
|
|
description="Bauteilart -> Anzahl, z. B. {'Separator': 1, 'Switch': 1}",
|
|
)
|
|
style: TroStyle = Field(
|
|
default=STYLE_EXT,
|
|
description="Farbgruppe fuer Zeichnungen (Graphviz, Mermaid, CAD-Symbol)",
|
|
)
|
|
symbol: str = Field(
|
|
default=TroSymbol.CIRCLE,
|
|
min_length=1,
|
|
description="Zeichensymbol des Markers im CAD, z. B. 'triangle'",
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
name: str | None = None,
|
|
fb_block: str | None = None,
|
|
items: dict[str, int] | None = None,
|
|
style: TroStyle | None = None,
|
|
symbol: str | None = None,
|
|
**data,
|
|
) -> None:
|
|
# Positionsargumente auf Feldnamen abbilden, damit die bisherige
|
|
# Aufrufform TroDefinition("1Sep", "FB_...", {...}) erhalten bleibt.
|
|
if name is not None:
|
|
data["name"] = name
|
|
if fb_block is not None:
|
|
data["fb_block"] = fb_block
|
|
if items is not None:
|
|
data["items"] = items
|
|
if style is not None:
|
|
data["style"] = style
|
|
if symbol is not None:
|
|
data["symbol"] = symbol
|
|
super().__init__(**data)
|
|
|
|
@field_validator("items", mode="after")
|
|
@classmethod
|
|
def _clean_items(cls, value: dict[str, int]) -> dict[str, int]:
|
|
"""Leere Bauteilarten ablehnen, Anzahlen <= 0 verwerfen."""
|
|
cleaned: dict[str, int] = {}
|
|
for item, count in value.items():
|
|
key = str(item).strip()
|
|
if not key:
|
|
raise ValueError("Bauteilart darf nicht leer sein")
|
|
if int(count) > 0:
|
|
cleaned[key] = int(count)
|
|
return cleaned
|
|
|
|
# -- get ---------------------------------------------------------------
|
|
|
|
def get_name(self) -> str:
|
|
"""Kurztyp, z. B. '1Sep1Swi'."""
|
|
return self.name
|
|
|
|
def get_fb_block(self) -> str:
|
|
"""Name des Siemens-Funktionsbausteins."""
|
|
return self.fb_block
|
|
|
|
def get_items(self) -> dict[str, int]:
|
|
"""Alle Bauteile als {Art: Anzahl} (Kopie - Aenderungen wirken nicht)."""
|
|
return dict(self.items)
|
|
|
|
def get_item_names(self) -> list[str]:
|
|
"""Enthaltene Bauteilarten, alphabetisch."""
|
|
return sorted(self.items)
|
|
|
|
def get_item_count(self, item: str) -> int:
|
|
"""Anzahl einer Bauteilart; 0 wenn nicht enthalten."""
|
|
return self.items.get(item, 0)
|
|
|
|
def has_item(self, item: str) -> bool:
|
|
"""Ist die Bauteilart enthalten?"""
|
|
return self.get_item_count(item) > 0
|
|
|
|
def get_item_fb(self, item: str) -> str:
|
|
"""Sub-Funktionsbaustein einer Bauteilart ('' wenn keiner)."""
|
|
return ITEM_FB.get(item, "")
|
|
|
|
def get_total_items(self) -> int:
|
|
"""Summe aller Bauteile."""
|
|
return sum(self.items.values())
|
|
|
|
def get_style(self) -> TroStyle:
|
|
"""Darstellung (Farbgruppe) dieses Typs."""
|
|
return self.style
|
|
|
|
def get_symbol(self) -> str:
|
|
"""Zeichensymbol des Markers, z. B. 'triangle'."""
|
|
return self.symbol
|
|
|
|
def get_group(self) -> str:
|
|
"""Kurzname der Farbgruppe, z. B. 'vario'."""
|
|
return self.style.group
|
|
|
|
def get_dot_attrs(self) -> dict[str, str]:
|
|
"""Graphviz-Knotenattribute dieses Typs."""
|
|
return self.style.dot_attrs()
|
|
|
|
# -- set ---------------------------------------------------------------
|
|
#
|
|
# Jede Zuweisung laeuft durch die Pydantic-Validierung, weil
|
|
# validate_assignment aktiv ist.
|
|
|
|
def set_name(self, name: str) -> None:
|
|
"""Kurztyp setzen."""
|
|
self.name = name
|
|
|
|
def set_fb_block(self, fb_block: str) -> None:
|
|
"""FB-Baustein setzen."""
|
|
self.fb_block = fb_block
|
|
|
|
def set_items(self, items: dict[str, int]) -> None:
|
|
"""Bauteilliste vollstaendig ersetzen."""
|
|
self.items = dict(items)
|
|
|
|
def set_style(self, style: TroStyle) -> None:
|
|
"""Darstellung (Farbgruppe) setzen."""
|
|
self.style = style
|
|
|
|
def set_symbol(self, symbol: str) -> None:
|
|
"""Zeichensymbol des Markers setzen."""
|
|
self.symbol = symbol
|
|
|
|
def set_item(self, item: str, count: int) -> None:
|
|
"""
|
|
Anzahl einer Bauteilart setzen.
|
|
|
|
count <= 0 entfernt das Bauteil. Unbekannte Arten sind erlaubt, damit
|
|
neue Bauteile ohne Aenderung an TroItem ergaenzt werden koennen.
|
|
"""
|
|
updated = dict(self.items)
|
|
key = str(item).strip()
|
|
if not key:
|
|
raise ValueError(f"{self.name}: Bauteilart darf nicht leer sein")
|
|
if int(count) <= 0:
|
|
updated.pop(key, None)
|
|
else:
|
|
updated[key] = int(count)
|
|
self.items = updated
|
|
|
|
def add_item(self, item: str, count: int = 1) -> None:
|
|
"""Anzahl einer Bauteilart erhoehen (oder Bauteil neu aufnehmen)."""
|
|
self.set_item(item, self.get_item_count(item) + int(count))
|
|
|
|
def remove_item(self, item: str) -> None:
|
|
"""Bauteilart entfernen."""
|
|
self.set_item(item, 0)
|
|
|
|
# -- Darstellung -------------------------------------------------------
|
|
|
|
def describe_items(self) -> str:
|
|
"""Bauteile als Text, z. B. '1x Separator, 1x Switch'."""
|
|
if not self.items:
|
|
return "-"
|
|
return ", ".join(f"{self.items[i]}x {i}" for i in self.get_item_names())
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Statische Typdefinition
|
|
# ---------------------------------------------------------------------------
|
|
#
|
|
# Quellen: doc/TRO_Typen.md (Baukasten-Analyse, Mapping-Tabelle) und
|
|
# doc/TRO_Katalog/scl_templates/*.scl (VAR-Deklarationen)
|
|
|
|
TRO_CATALOG: tuple[TroDefinition, ...] = (
|
|
# Basistyp: 1x Separator plus das Rahmenwerk, das jeder Typ besitzt
|
|
# (PriorityManager, JamArea Entry/Exit, HMI, Safety, MachineState).
|
|
TroDefinition("1Sep", "FB_ILS_MTRO_1Sep", {
|
|
TroItem.SEPARATOR: 1,
|
|
}, STYLE_SEP, TroSymbol.CIRCLE),
|
|
# laut TRO_Typen.md: Basis + 1x Switch-Modul
|
|
TroDefinition("1Sep1Swi", "FB_ILS_MTRO_1Sep1Swi", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.SWITCH: 1,
|
|
}, STYLE_SWI, TroSymbol.TRIANGLE),
|
|
# laut TRO_Typen.md: Basis + 2x Switch-Modul + Scanner-Modul
|
|
TroDefinition("1Sep2Swi", "FB_ILS_MTRO_1Sep2Swi", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.SWITCH: 2,
|
|
TroItem.SCANNER: 1,
|
|
}, STYLE_SWI, TroSymbol.PENTAGON),
|
|
# laut TRO_Typen.md: Basis + Scanner-Modul + SSCC-Modul (Messsensor + WCS)
|
|
TroDefinition("1Sep_SSCC", "FB_ILS_MTRO_1Sep_SSCC", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.SCANNER: 1,
|
|
TroItem.SSCC: 1,
|
|
}, STYLE_SSCC, TroSymbol.DOUBLE_CIRCLE),
|
|
# laut TRO_Typen.md: Basis + Vario-Antriebsmodul
|
|
TroDefinition("Vario", "FB_ILS_MTRO_Vario", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.VARIO_DRIVE: 1,
|
|
}, STYLE_VARIO, TroSymbol.RECT),
|
|
# laut TRO_Typen.md: Basis (Pin-Separator) + 19x Storage-Line + Scanner
|
|
# + Encoder + StorageRemoval-Schnittstelle
|
|
TroDefinition("PinStore_Auto", "FB_ILS_MTRO_PinStore_Auto", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.STORAGE_LINE: 19,
|
|
TroItem.SCANNER: 1,
|
|
TroItem.ENCODER: 1,
|
|
}, STYLE_STORE, TroSymbol.SQUARE),
|
|
# aus SCL belegt (FB_ILS_MTRO_Vario_workStation.scl, VAR ab Zeile 77):
|
|
# fbSeparator1, fbConvVario, fbSepWait, fbBarcodeReader.
|
|
# Der Vario-Antrieb ist hier die WorkStation-Variante des STRO-Bausteins.
|
|
TroDefinition("Vario_workStation", "FB_ILS_MTRO_Vario_workStation", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.VARIO_DRIVE: 1,
|
|
TroItem.WORK_STATION: 1,
|
|
TroItem.ACCUMULATE: 1,
|
|
TroItem.SCANNER: 1,
|
|
}, STYLE_VARIO, TroSymbol.HEXAGON),
|
|
# aus SCL belegt (FB_EmptyCarrBuffer.scl): arfbSeparatorStorage als
|
|
# Array[1..5] of FB_ILS_STRO_Sep + 5x fbCarrierWaitStore.
|
|
# Kein eigener Eingangs-Separator - der "inTro" ist ein separater 1Sep-TRO
|
|
# (in der Referenzanlage z. B. TRO101_IN neben TRO101).
|
|
TroDefinition("EmptyCarrBuffer", "FB_EmptyCarrBuffer", {
|
|
TroItem.STORAGE_LINE: 5,
|
|
TroItem.ACCUMULATE: 5,
|
|
}, STYLE_STORE, TroSymbol.DIAMOND),
|
|
# aus SCL belegt (FB_LoadingBoom_INBOUND.scl): fbTiltSensor,
|
|
# fbDistanceFoot, fbWorkSation. Bewusst KEIN Separator und KEINE Weiche -
|
|
# der einzige nicht additive Typ.
|
|
TroDefinition("LoadingBoom", "FB_LoadingBoom_INBOUND", {
|
|
TroItem.BOOM: 1,
|
|
TroItem.FOOT: 1,
|
|
TroItem.TILT_SENSOR: 1,
|
|
}, STYLE_EXT, TroSymbol.ARROW),
|
|
# aus SCL belegt (FB_ILS_MTRO_2Sep1Swi.scl, VAR ab Zeile 115):
|
|
# fbSeparator1, fbSeparator2, fbSwitch1, fbBarcodeReader1, fbBarcodeReader2.
|
|
# Die Mapping-Tabelle in TRO_Typen.md nennt die beiden Scanner nicht -
|
|
# hier gilt der Code.
|
|
TroDefinition("2Sep1Swi", "FB_ILS_MTRO_2Sep1Swi", {
|
|
TroItem.SEPARATOR: 2,
|
|
TroItem.SWITCH: 1,
|
|
TroItem.SCANNER: 2,
|
|
}, STYLE_SWI, TroSymbol.TRIANGLE_DOWN),
|
|
# ACHTUNG - NICHT aus SCL belegt. Alle Typen oberhalb stammen aus
|
|
# vorhandenem Code bzw. der Mapping-Tabelle in TRO_Typen.md; dieser hier
|
|
# wurde am 2026-08-12 auf Anforderung aus dem Projekt 500573 (Mubea)
|
|
# aufgenommen, um zwei Uebergabestellen am Beruehrpunkt Kreisel2/Kreisel1
|
|
# zu einem Steuerobjekt zusammenzufassen.
|
|
# Der Baustein FB_ILS_MTRO_2Sep2Swi existiert in diesem Repository nicht
|
|
# und ist auch in doc/TRO_Katalog/scl_templates/ nicht hinterlegt - er muss
|
|
# in der ILSLib angelegt werden, sonst erzeugt ein spaeterer
|
|
# SCL-Generator einen Aufruf auf einen fehlenden Baustein.
|
|
TroDefinition("2Sep2Swi", "FB_ILS_MTRO_2Sep2Swi", {
|
|
TroItem.SEPARATOR: 2,
|
|
TroItem.SWITCH: 2,
|
|
TroItem.SCANNER: 2,
|
|
}, STYLE_SWI, TroSymbol.DOUBLE_TRIANGLE_DOWN),
|
|
)
|
|
|
|
_BY_NAME: dict[str, TroDefinition] = {t.get_name(): t for t in TRO_CATALOG}
|
|
|
|
|
|
def get_tro(name: str) -> TroDefinition | None:
|
|
"""Typdefinition nach Namen; None wenn unbekannt."""
|
|
return _BY_NAME.get(name)
|
|
|
|
|
|
def tro_names() -> list[str]:
|
|
"""Alle Typnamen in Katalogreihenfolge."""
|
|
return [t.get_name() for t in TRO_CATALOG]
|
|
|
|
|
|
def set_tro(definition: TroDefinition) -> None:
|
|
"""Typdefinition ergaenzen oder ersetzen (nur zur Laufzeit)."""
|
|
_BY_NAME[definition.get_name()] = definition
|
|
|
|
|
|
|
|
def catalog() -> dict[str, TroDefinition]:
|
|
"""Alle Typdefinitionen als {Name: TroDefinition} (Kopie der Zuordnung)."""
|
|
return dict(_BY_NAME)
|
|
|
|
|
|
def mermaid_classdefs() -> list[str]:
|
|
"""classDef-Zeilen fuer ein Mermaid-Diagramm, eine je Farbgruppe."""
|
|
return [style.mermaid_classdef() for style in STYLES]
|