From 25ab362c0a17d1ae5c682b3e457ee7a268ecc3ac Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Wed, 28 Oct 2026 23:13:02 +0100 Subject: [PATCH] scl_templates: Aufruf-Template FB_ILS_MTRO_2Sep2Swi (ohne Referenz-Aufrufstelle) Mubea wird damit vollstaendig aus Templates erzeugt. Der FB existiert noch nicht in der ILSLib; die Schnittstelle ist aus 2Sep1Swi (Separatoren) und 1Sep2Swi (Weichen) angenommen und steht im Template-Kopf - mit den SPS-Kollegen abzustimmen. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 9 +- doc/Python_Scripts.md | 13 +- doc/SCL_Templates.md | 21 ++-- lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2 | 115 ++++++++++++++++++ lib/tro_catalog.py | 3 +- .../fixtures/scl/mubea_FB_Main_templates.scl | 97 +++++++++------ tests/test_scl_skeleton_golden.py | 9 +- 7 files changed, 215 insertions(+), 52 deletions(-) create mode 100644 lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2 diff --git a/CLAUDE.md b/CLAUDE.md index d1dc3a5..b226277 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -180,9 +180,12 @@ Inside the SCL output, `lib/scl_context.py` (TRO-JSON → render context, all de sits between `model.py` and `scl_skeleton.py` (context → text only). With `--templates` (opt-in) REGIONs come from Jinja2 templates in `lib/scl_templates/.scl.j2` (all 7 types with a reference call site: `1Sep`, `1Sep1Swi`, `1Sep2Swi`, `1Sep_SSCC`, -`Vario`, `Vario_workStation`, `PinStore_Auto`; `2Sep1Swi`, `EmptyCarrBuffer`, `LoadingBoom`, -`2Sep2Swi` stay generic until a call site exists), each round-trip tested against its reference call site -in `doc/TRO_Katalog/scl_templates/` (`tests/test_scl_templates.py`); every line holding a +`Vario`, `Vario_workStation`, `PinStore_Auto`; `2Sep1Swi`, `EmptyCarrBuffer`, `LoadingBoom` +stay generic until a call site exists), each round-trip tested against its reference call site +in `doc/TRO_Katalog/scl_templates/` (`tests/test_scl_templates.py`). Exception: `2Sep2Swi` +has a template WITHOUT reference call site (the FB does not exist in the ILSLib yet - its +interface is assumed from `2Sep1Swi` + `1Sep2Swi`, see the template header; only covered by +rendering the real plants and the golden file); every line holding a placeholder must carry `TODO(E-Planung)`. Migration steps, decisions per template line and status: `doc/SCL_Templates.md`. Golden files in `tests/fixtures/scl/` pin the SCL output byte for byte — rewrite them (`SKEL_UPDATE_GOLDEN=1`) only for a reviewed, intended change. diff --git a/doc/Python_Scripts.md b/doc/Python_Scripts.md index cedee50..5798416 100644 --- a/doc/Python_Scripts.md +++ b/doc/Python_Scripts.md @@ -626,8 +626,10 @@ with a real reference call site (`1Sep`, `1Sep1Swi`, `1Sep2Swi`, `1Sep_SSCC`, `Vario`, `Vario_workStation`, `PinStore_Auto`); each follows its call site in `doc/TRO_Katalog/scl_templates/` line for line, and every value that is still open carries `TODO(E-Planung)`. The line decisions are proposals to be confirmed -by a PLC engineer (`doc/SCL_Templates.md` §6). `2Sep1Swi`, `EmptyCarrBuffer`, -`LoadingBoom` and `2Sep2Swi` have no call site yet and stay generic. `--strict` stops (exit `1`, no SCL) if any FB type has no +by a PLC engineer (`doc/SCL_Templates.md` §6). `2Sep1Swi`, `EmptyCarrBuffer` and +`LoadingBoom` have no call site yet and stay generic. `2Sep2Swi` has a template without +a call site (FB not yet in the ILSLib, interface assumed from `2Sep1Swi` + `1Sep2Swi`). +`--strict` stops (exit `1`, no SCL) if any FB type has no template. Without `--templates` the output is unchanged. **Names from the plant JSON (stage 4, `--json _anlage.json`).** The @@ -975,8 +977,11 @@ verified against `data/*.scl` where the source is vendored locally, and against > Kreisel2/Kreisel1 touch as a single control object with 2 separators, > 2 scanners and 2 switches. **`FB_ILS_MTRO_2Sep2Swi` does not exist** in this > repository or in `doc/TRO_Katalog/scl_templates/`, and has to be created in -> the ILSLib — otherwise a future SCL generator will emit a call to a missing -> block. The closest verified type is `2Sep1Swi` (2 separators, 2 scanners, +> the ILSLib — otherwise the generated FB_Main calls a missing block. Since +> 2026-10-28 there is a call-site template `lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2` +> whose header lists the assumed interface (separators as in `2Sep1Swi`, switches +> as in `1Sep2Swi`) - the FB has to be created to match it, or the template +> adjusted. The closest verified type is `2Sep1Swi` (2 separators, 2 scanners, > **1** switch), which matches the hardware actually present in that export. > `3Sep2Swi` (3 separators, 3 scanners, 2 switches) was added on 2026-10-14 > for the test plant `data/export.csv`, where one Kreisel pulley touches two diff --git a/doc/SCL_Templates.md b/doc/SCL_Templates.md index 9f20b30..5a127de 100644 --- a/doc/SCL_Templates.md +++ b/doc/SCL_Templates.md @@ -66,10 +66,12 @@ Coverage per catalog type (`lib/tro_catalog.py`): | `2Sep1Swi` | `FB_ILS_MTRO_2Sep1Swi` | **no** | yes | from interface only — needs a real call site | | `EmptyCarrBuffer` | `FB_EmptyCarrBuffer` | **no** | yes | from interface only — needs a real call site | | `LoadingBoom` | `FB_LoadingBoom_INBOUND` | **no** | yes | from interface only — needs a real call site | -| `2Sep2Swi` | `FB_ILS_MTRO_2Sep2Swi` | **no** | **no** | no — FB does not exist yet (Mubea needs it) | +| `2Sep2Swi` | `FB_ILS_MTRO_2Sep2Swi` | **no** | **no** | ✅ done WITHOUT reference (2026-10-28) — FB does not exist yet (Mubea needs it); interface assumed from `2Sep1Swi` (separators) + `1Sep2Swi` (switches), see template header | So 7 types can be done with a test against real code. 3 can only be checked against the -interface until someone supplies a real call site. `2Sep2Swi` stays on the fallback (§9). +interface until someone supplies a real call site. `2Sep2Swi` has a template that is only +covered by rendering the real plants and the mubea golden file - the FB has to be created +in the ILSLib to match its assumed interface (or the template adjusted). --- @@ -410,14 +412,15 @@ as `carousel_run` from connection kinds). | Situation | Behaviour | Exit | |---|---|---| | Template exists for the TRO's `fbType` | render template | 0 | -| No template (e.g. `2Sep2Swi`) | render with the current `emit_*` code; header lines `// Aus Template : …` / `// Generisch : … (kein Template - von Hand pruefen)` and an entry in the console summary | 0 | +| No template (e.g. `2Sep1Swi`) | render with the current `emit_*` code; header lines `// Aus Template : …` / `// Generisch : … (kein Template - von Hand pruefen)` and an entry in the console summary | 0 | | No template **and** `--strict` | stop, write nothing | 1 | | Template uses an undefined variable / syntax error | stop, write nothing, show template file and line | 1 | | Naming rule with unknown placeholder | stop, write nothing | 1 | | Invalid TRO-JSON | unchanged from today | 1 | With `--templates` the console summary gets a `Templates` line (implemented); the -`Namensregeln` line follows with step 4. Real output for mubea today: +`Namensregeln` line follows with step 4. Real output for mubea before the `2Sep2Swi` +template (since 2026-10-28 mubea is fully rendered from templates): ``` Templates = 4 von 5 Typen (generisch: FB_ILS_MTRO_2Sep2Swi) @@ -452,9 +455,9 @@ Each step ends with all tests green and is usable on its own. | 2 ✅ | `scl_context.py`: build the render context from `TroDocument`; `emit_*` read from it — `tests/test_scl_context.py` | golden files byte-identical (also checked on dematic and showroom, with and without `--start`) | | 3 ✅ | Pilot `FB_ILS_MTRO_1Sep1Swi.scl.j2` + `_macros`; switches `--templates`, `--strict`; class-C table (§6) filled with proposals — **still to be confirmed by a PLC engineer**; round-trip test | round trip against TRO107 passes; only the 1Sep1Swi REGIONs (+ header) differ from the generic golden files | | 4 | `scl_naming.py` + `cfg/scl_naming.ini`; switch `--naming` | naming tests pass; Mubea renders with names instead of TODOs where a rule exists | -| 5 ✅ | Remaining call-site templates (`1Sep`, `Vario`, `1Sep2Swi`, `1Sep_SSCC`, `Vario_workStation`, `PinStore_Auto`), each with round trip against its reference (`PinStore_Auto`: the parts the reference abbreviates are left out of the comparison); decisions in §6 — **still to be confirmed by a PLC engineer**. Interface check (§8.2) for `Vario_workStation` still open | every round trip passes; HundM05 fully from templates, mubea except `2Sep2Swi` | +| 5 ✅ | Remaining call-site templates (`1Sep`, `Vario`, `1Sep2Swi`, `1Sep_SSCC`, `Vario_workStation`, `PinStore_Auto`), each with round trip against its reference (`PinStore_Auto`: the parts the reference abbreviates are left out of the comparison); decisions in §6 — **still to be confirmed by a PLC engineer**. Interface check (§8.2) for `Vario_workStation` still open | every round trip passes; HundM05 fully from templates, mubea too since the `2Sep2Swi` template (2026-10-28, no reference) | | 6 | Templates on by default; new `--no-templates` keeps the old path for one release | golden files updated and reviewed; one import into TIA Portal (as for Mubea) | -| 7 | Remove `emit_*` once every type in use has a template (`2Sep2Swi` needs a call site first) | fallback only for types without FB | +| 7 | Remove `emit_*` once every type in use has a template (`2Sep2Swi` has one, but without call site - confirm it once the FB exists) | fallback only for types without FB | Docs touched along the way: `doc/Python_Scripts.md` §5b, `doc/Commandlines.md` §2.5, `CLAUDE.md` (roadmap), this file. @@ -511,8 +514,10 @@ jam-area DBs) until an E-Planung export exists, and the `pruefen` timings. 4. `xInRelease`: `TRUE` as in the reference, or the `"DB_TRO_TEST"` test release used today? 5. Real call sites for `2Sep1Swi`, `EmptyCarrBuffer`, `LoadingBoom` — available from another plant? -6. `FB_ILS_MTRO_2Sep2Swi` (Mubea): will it be created in the ILSLib, or should the two - transfer points be modelled with existing types? +6. `FB_ILS_MTRO_2Sep2Swi` (Mubea): to be created in the ILSLib (decided 2026-10-28, + the two transfer points stay one TRO). Its call site is drafted in + `lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2`; open: the assumed interface + (`bSepType`, `stInOutCognexInterface1/2`, priority manager, `xNewSwitch`). 7. `nTo1Destinations`: TRO107 has 2 exits but the value 3 ("Info noetig fuer HMI"). Does it count the destinations behind the switch rather than its exits? If so, which destinations — the per-exit target lists in the skeleton could supply them. diff --git a/lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2 b/lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2 new file mode 100644 index 0000000..a893d39 --- /dev/null +++ b/lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2 @@ -0,0 +1,115 @@ +{#- + FB_ILS_MTRO_2Sep2Swi - Aufrufstelle in FB_Main + + ACHTUNG: KEINE Referenz-Aufrufstelle. Der Baustein existiert noch nicht in der + ILSLib (Anlass: Mubea 500573, Beruehrpunkt Kreisel2/Kreisel1 - zwei + Separatoren laufen auf Ausschleuselement und Kreisel-Weiche zu). Darum gibt es + hier keinen Rundlauf-Test wie bei den anderen Templates, nur das Rendern fuer + die echten Anlagen (tests/test_scl_templates.py) und die Golden-Datei. + + Die Schnittstelle ist aus den beiden Nachbarbausteinen ZUSAMMENGESETZT und + muss beim Anlegen des FB so (oder geaendert hier) umgesetzt werden: + zwei Separatoren wie FB_ILS_MTRO_2Sep1Swi (Quelle data/): stInSeparator1/2, + stInSettings.bSep1Type/bSep2Type, arInOutJamEntr1/2, + stInBarcodeReader1/2, stInOutCognexInterface1/2, + xOutStopper1/2 + zwei Weichen wie FB_ILS_MTRO_1Sep2Swi (Referenz TRO 267): stInSwitch1/2 + mit xNewSwitch, stInSenJam und arInOutJamExit je + Ausgang, xInCarouselRun1/2, xOutSw1ExTo3/xOutSw2ExTo3 + Entscheidungen zu den ortsgebundenen Zeilen (doc/SCL_Templates.md §6): + Separatorzeiten 100/50 ms wie die anderen Templates (m.separator), "pruefen" + nSwitchNo fuer BEIDE Weichen (FC_Direction braucht die Nummer; + in TRO 267 fehlt sie bei Weiche 2 - dort offen, Frage 9) + nTo1Destinations Aufteilung der Abgaenge auf die Weichen offen + bSepType.%X2 TRUE wie bSepType.%X2 in TRO 267, Bedeutung klaeren + xInCarouselRun je Weiche einer - hier sitzen beide an je einem Kreisel + Vorfahrtsregelung nicht verdrahtet: 2Sep1Swi hat stInPriorityManagerDir1..4, + 1Sep2Swi ein einzelnes stInPriorityManager - offen + FC_Direction je Weiche einer, Ziel nInDirection1/2 + Alle noch mit den SPS-Kollegen zu bestaetigen. +-#} +{% import "_macros.scl.j2" as m %} +REGION {{ t.region_title }} +{{ m.kopf(t) }} + // ACHTUNG: FB_ILS_MTRO_2Sep2Swi existiert noch nicht in der ILSLib - Schnittstelle + // angenommen (2Sep1Swi + 1Sep2Swi), mit den SPS-Kollegen abzustimmen. + +{% for s in t.separators %} +{{ m.separator(t, s) }} +{% if not loop.last %} + +{% endif %} +{% endfor %} +{{ m.jam_sensors(t) }} + +{% for w in t.switches %} + #{{ t.id }}.stInSwitch{{ w.n }}.Settings.nSwitchNo := "{{ w.no.value }}";{{ m.todo(w.no) }} + #{{ t.id }}.stInSwitch{{ w.n }}.Settings.xPluggedExSen3 := FALSE; + #{{ t.id }}.stInSwitch{{ w.n }}.Settings.xPluggedExSen4 := FALSE; + #{{ t.id }}.stInSwitch{{ w.n }}.Settings.xNewSwitch := TRUE; +{% if w.to1_destinations is not none %} + #{{ t.id }}.stInSwitch{{ w.n }}.Settings.nTo1Destinations := {{ w.to1_destinations }}; // Info noetig fuer HMI - {{ TODO }}: pruefen +{% else %} + #{{ t.id }}.stInSwitch{{ w.n }}.Settings.nTo1Destinations := _; // {{ TODO }}: {{ t.successors|length }} Abgaenge auf {{ t.switches|length }} Weichen - Aufteilung festlegen +{% endif %} + +{% endfor %} +{{ m.ziele(t) }} + +{% for sc in t.scanners %} + #{{ t.id }}.stInBarcodeReader{{ sc.n }}.Settings.xActivateCheckASCI := TRUE; + #{{ t.id }}.stInBarcodeReader{{ sc.n }}.Settings.tTimeout := T#5s; + +{{ m.cognex_in(m.cognex(sc), sc) }} + +{% endfor %} + // Vorfahrtsregelung: nicht verdrahtet - {{ TODO }}: Schnittstelle des FB klaeren +{% for s in t.separators %} + #{{ t.id }}.stInSettings.bSep{{ s.n }}Type.%X2 := TRUE; // {{ TODO }}: pruefen (Bedeutung) +{% endfor %} + +{% set z = [] %} +{% set _ = z.append(('nInMainTroNo := "' ~ t.main_tro.value ~ '"', m.note(t.main_tro))) %} +{% set _ = z.append(("xInSftyOk := " ~ t.safety.value, m.note(t.safety))) %} +{% set _ = z.append(("xInAllRdyToStart := TRUE", "")) %} +{% set _ = z.append(('xInCancel := "cTodoFalse"', "")) %} +{% set _ = z.append(("xInRelease := " ~ t.release, "")) %} +{% for w in t.switches %} +{% set _ = z.append(("xInCarouselRun" ~ w.n ~ " := " ~ t.carousel_run.value, m.note(t.carousel_run, "Kreisel an Weiche " ~ w.n))) %} +{% endfor %} +{% set _ = z.append(("stInOutMachineState := " ~ t.machine_state.value, m.note(t.machine_state, "Schaltschrank"))) %} +{% for s in t.separators %} +{% if t.scanners|length >= s.n %} +{% set sc = t.scanners[s.n - 1] %} +{% set _ = z.append(("stInOutCognexInterface" ~ s.n ~ " := " ~ m.cognex(sc), m.note(sc.interface))) %} +{% else %} +{% set _ = z.append(("stInOutCognexInterface" ~ s.n ~ " := #stCognexInterfaceDummy", "")) %} +{% endif %} +{% endfor %} +{% for j in t.jam_entries %} +{% set _ = z.append(("arInOutJamEntr" ~ j.n ~ " := " ~ j.carriers.value, m.note(j.carriers, j.title ~ " von " ~ j.neighbour))) %} +{% set _ = z.append(("stInOutJamEntr" ~ j.n ~ " := " ~ j.data.value, m.note(j.data))) %} +{% endfor %} +{% for j in t.jam_exits %} +{% set _ = z.append(("arInOutJamExit" ~ j.n ~ " := " ~ j.carriers.value, m.note(j.carriers, j.title ~ " vor " ~ j.neighbour))) %} +{% set _ = z.append(("stInOutJamExit" ~ j.n ~ " := " ~ j.data.value, m.note(j.data))) %} +{% endfor %} +{% for s in t.separators %} +{% set _ = z.append(("xOutStopper" ~ s.n ~ ' => "' ~ s.stopper.value ~ '"', m.note(s.stopper))) %} +{% endfor %} +{% for w in t.switches %} +{% set _ = z.append(("xOutSw" ~ w.n ~ 'ExTo3 => "' ~ w.valve.value ~ '"', m.note(w.valve))) %} +{% endfor %} +{% set _ = z.append(('stInOutHMI := "DB_Interface_HMI".stTRO.' ~ t.id, "")) %} +{% set _ = z.append(('nOutStateLast => "DB_GLOB_TroState".arTroState["' ~ t.main_tro.value ~ '"]', m.note(t.main_tro))) %} +{{ m.call(t, z) }} + +{% for sc in t.scanners %} +{{ m.cognex_out(m.cognex(sc), sc) }} +{% if not loop.last %} + +{% endif %} +{% endfor %} + +{{ m.direction(t) }} +END_REGION diff --git a/lib/tro_catalog.py b/lib/tro_catalog.py index 0cdd4a2..81bd11e 100644 --- a/lib/tro_catalog.py +++ b/lib/tro_catalog.py @@ -613,7 +613,8 @@ TRO_CATALOG: tuple[TroDefinition, ...] = ( # 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. + # SCL-Generator einen Aufruf auf einen fehlenden Baustein. Die angenommene + # Schnittstelle steht im Kopf von lib/scl_templates/FB_ILS_MTRO_2Sep2Swi.scl.j2. TroDefinition("2Sep2Swi", "FB_ILS_MTRO_2Sep2Swi", { TroItem.SEPARATOR: 2, TroItem.SWITCH: 2, diff --git a/tests/fixtures/scl/mubea_FB_Main_templates.scl b/tests/fixtures/scl/mubea_FB_Main_templates.scl index f8536fa..8b1f8c9 100644 --- a/tests/fixtures/scl/mubea_FB_Main_templates.scl +++ b/tests/fixtures/scl/mubea_FB_Main_templates.scl @@ -16,8 +16,8 @@ // Reihenfolge der REGIONs = Materialfluss. // Anfang bei TRO03: Materialeingang ueber SYS1. // -// Aus Template : FB_ILS_MTRO_1Sep, FB_ILS_MTRO_1Sep1Swi, FB_ILS_MTRO_PinStore_Auto, FB_ILS_MTRO_Vario -// Generisch : FB_ILS_MTRO_2Sep2Swi (kein Template - von Hand pruefen) +// Aus Template : FB_ILS_MTRO_1Sep, FB_ILS_MTRO_1Sep1Swi, FB_ILS_MTRO_2Sep2Swi, FB_ILS_MTRO_PinStore_Auto, FB_ILS_MTRO_Vario +// Generisch : - (kein Template - von Hand pruefen) // ============================================================ FUNCTION_BLOCK "FB_Main" @@ -514,42 +514,46 @@ REGION TRO10 (2Sep2Swi) Sep 0005, 0036 // Vorgaenger: TRO01, TRO06, TRO18 // Nachfolger: TRO01, TRO02, TRO11 // Einstufung: hoch + // Aufbau nach Template FB_ILS_MTRO_2Sep2Swi.scl.j2 (Referenz: doc/TRO_Katalog/scl_templates) + // ACHTUNG: FB_ILS_MTRO_2Sep2Swi existiert noch nicht in der ILSLib - Schnittstelle + // angenommen (2Sep1Swi + 1Sep2Swi), mit den SPS-Kollegen abzustimmen. // Separator 1 = Bauteil 0005 aus dem Layout - #TRO10.stInSeparator1.Settings.nSeparatorNo := "cSep_____"; // TODO(E-Planung) + #TRO10.stInSeparator1.Settings.nSeparatorNo := "cSep_____"; // TODO(E-Planung) #TRO10.stInSeparator1.Settings.tDelayToNextItem := "TimeForSepWaiting_Short"; - #TRO10.stInSeparator1.Settings.tTrailingTime := t#600ms; // TODO(E-Planung): pruefen - #TRO10.stInSeparator1.Settings.tHandlingTime := t#200ms; // TODO(E-Planung): pruefen + #TRO10.stInSeparator1.Settings.tTrailingTime := t#100ms; // TODO(E-Planung): pruefen + #TRO10.stInSeparator1.Settings.tHandlingTime := t#50ms; // TODO(E-Planung): pruefen #TRO10.stInSeparator1.Settings.tJam := "TimeForSepJam"; #TRO10.stInSeparator1.Settings.xPluggedJam := TRUE; #TRO10.stInSeparator1.Settings.xPluggedPart := FALSE; #TRO10.stInSeparator1.Settings.xPluggedScanner := TRUE; #TRO10.stInSeparator1.stSenInSep := "DB_Inputs".Sensors["cInBG____"]; // TODO(E-Planung) - #TRO10.stInSeparator1.Settings.tSenFree := T#1500ms; // TODO(E-Planung): pruefen - #TRO10.stInSeparator1.Settings.tSenWait := T#4000ms; // TODO(E-Planung): pruefen // Separator 2 = Bauteil 0036 aus dem Layout - #TRO10.stInSeparator2.Settings.nSeparatorNo := "cSep_____"; // TODO(E-Planung) + #TRO10.stInSeparator2.Settings.nSeparatorNo := "cSep_____"; // TODO(E-Planung) #TRO10.stInSeparator2.Settings.tDelayToNextItem := "TimeForSepWaiting_Short"; - #TRO10.stInSeparator2.Settings.tTrailingTime := t#600ms; // TODO(E-Planung): pruefen - #TRO10.stInSeparator2.Settings.tHandlingTime := t#200ms; // TODO(E-Planung): pruefen + #TRO10.stInSeparator2.Settings.tTrailingTime := t#100ms; // TODO(E-Planung): pruefen + #TRO10.stInSeparator2.Settings.tHandlingTime := t#50ms; // TODO(E-Planung): pruefen #TRO10.stInSeparator2.Settings.tJam := "TimeForSepJam"; #TRO10.stInSeparator2.Settings.xPluggedJam := TRUE; #TRO10.stInSeparator2.Settings.xPluggedPart := FALSE; #TRO10.stInSeparator2.Settings.xPluggedScanner := TRUE; #TRO10.stInSeparator2.stSenInSep := "DB_Inputs".Sensors["cInBG____"]; // TODO(E-Planung) - #TRO10.stInSeparator2.Settings.tSenFree := T#1500ms; // TODO(E-Planung): pruefen - #TRO10.stInSeparator2.Settings.tSenWait := T#4000ms; // TODO(E-Planung): pruefen + #TRO10.stInSenJam2 := "DB_Inputs".Sensors["cInBG____"]; // TODO(E-Planung) + #TRO10.stInSenJam3 := "DB_Inputs".Sensors["cInBG____"]; // TODO(E-Planung) + #TRO10.stInSenJam4 := "DB_Inputs".Sensors["cInBG____"]; // TODO(E-Planung) - #TRO10.stInSwitch1.Settings.nSwitchNo := "cSwi_____"; // TODO(E-Planung) + #TRO10.stInSwitch1.Settings.nSwitchNo := "cSwi_____"; // TODO(E-Planung) #TRO10.stInSwitch1.Settings.xPluggedExSen3 := FALSE; #TRO10.stInSwitch1.Settings.xPluggedExSen4 := FALSE; - #TRO10.stInSwitch1.Settings.nTo1Destinations := _; // TODO(E-Planung): dieser TRO hat 3 Abgaenge auf 2 Weichen - Aufteilung festlegen + #TRO10.stInSwitch1.Settings.xNewSwitch := TRUE; + #TRO10.stInSwitch1.Settings.nTo1Destinations := _; // TODO(E-Planung): 3 Abgaenge auf 2 Weichen - Aufteilung festlegen - #TRO10.stInSwitch2.Settings.nSwitchNo := "cSwi_____"; // TODO(E-Planung) + #TRO10.stInSwitch2.Settings.nSwitchNo := "cSwi_____"; // TODO(E-Planung) #TRO10.stInSwitch2.Settings.xPluggedExSen3 := FALSE; #TRO10.stInSwitch2.Settings.xPluggedExSen4 := FALSE; - #TRO10.stInSwitch2.Settings.nTo1Destinations := _; // TODO(E-Planung): dieser TRO hat 3 Abgaenge auf 2 Weichen - Aufteilung festlegen + #TRO10.stInSwitch2.Settings.xNewSwitch := TRUE; + #TRO10.stInSwitch2.Settings.nTo1Destinations := _; // TODO(E-Planung): 3 Abgaenge auf 2 Weichen - Aufteilung festlegen // Zielliste je Abgang (aus dem TRO-Graphen berechnet) - // Grundlage fuer die Zuordnung Ziel -> Richtung in FC_Direction: @@ -558,31 +562,47 @@ REGION TRO10 (2Sep2Swi) Sep 0005, 0036 // ueber TRO11: TRO03, TRO04, TRO05, TRO07, TRO11, TRO12, TRO18 #TRO10.stInBarcodeReader1.Settings.xActivateCheckASCI := TRUE; - #TRO10.stInBarcodeReader1.Settings.tTimeout := T#3000ms; - // TODO(E-Planung): Cognex-Interface verdrahten (#arCognexInterface["cScanner____"]) + #TRO10.stInBarcodeReader1.Settings.tTimeout := T#5s; + + #arCognexInterface["cScanner____"].xInCamTriggerReady := "bx____-TriggerReady"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].xInCamTriggerAck := "bx____-TriggerAck"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].xInCamResultsAvailable := "bx____-Results Available"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].xInCamGeneralFault := "bx____-General Fault"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].hwInCamInspectionResults := "BX____~Ergebnisse_–_64_Bytes_1"; // TODO(E-Planung) #TRO10.stInBarcodeReader2.Settings.xActivateCheckASCI := TRUE; - #TRO10.stInBarcodeReader2.Settings.tTimeout := T#3000ms; - // TODO(E-Planung): Cognex-Interface verdrahten (#arCognexInterface["cScanner____"]) + #TRO10.stInBarcodeReader2.Settings.tTimeout := T#5s; - #TRO10.stInPriorityManager.xReleaseOk := TRUE; + #arCognexInterface["cScanner____"].xInCamTriggerReady := "bx____-TriggerReady"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].xInCamTriggerAck := "bx____-TriggerAck"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].xInCamResultsAvailable := "bx____-Results Available"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].xInCamGeneralFault := "bx____-General Fault"; // TODO(E-Planung) + #arCognexInterface["cScanner____"].hwInCamInspectionResults := "BX____~Ergebnisse_–_64_Bytes_1"; // TODO(E-Planung) + + // Vorfahrtsregelung: nicht verdrahtet - TODO(E-Planung): Schnittstelle des FB klaeren + #TRO10.stInSettings.bSep1Type.%X2 := TRUE; // TODO(E-Planung): pruefen (Bedeutung) + #TRO10.stInSettings.bSep2Type.%X2 := TRUE; // TODO(E-Planung): pruefen (Bedeutung) #TRO10(nInMainTroNo := "cMainTro____", // TODO(E-Planung) xInSftyOk := "DB_InterfaceSafety".stFromSafety.EStopMain.Q, // TODO(E-Planung) xInAllRdyToStart := TRUE, + xInCancel := "cTodoFalse", xInRelease := "DB_TRO_TEST".TRO10, - stInOutMachineState := #stInOutControlUnitCabinet, - stInOutCognexInterface := #stCognexInterfaceDummy, + xInCarouselRun1 := #fbCarousel____.xOutConveyorFullSpeed, // TODO(E-Planung) - Kreisel an Weiche 1 + xInCarouselRun2 := #fbCarousel____.xOutConveyorFullSpeed, // TODO(E-Planung) - Kreisel an Weiche 2 + stInOutMachineState := #stInOutControlUnitCabinet, // TODO(E-Planung) - Schaltschrank + stInOutCognexInterface1 := #arCognexInterface["cScanner____"], // TODO(E-Planung) + stInOutCognexInterface2 := #arCognexInterface["cScanner____"], // TODO(E-Planung) arInOutJamEntr1 := "DB_JamArea____".stJam____.arCarrier, // TODO(E-Planung) - Staubereich J0005 von TRO01, TRO06, TRO18 (Aufteilung der Vorgaenger auf die Eingaenge offen) - stInOutJamEntr1 := "DB_JamArea____".stJam____.stData, + stInOutJamEntr1 := "DB_JamArea____".stJam____.stData, // TODO(E-Planung) arInOutJamEntr2 := "DB_JamArea____".stJam____.arCarrier, // TODO(E-Planung) - Staubereich J0036 von - (Aufteilung der Vorgaenger auf die Eingaenge offen) - stInOutJamEntr2 := "DB_JamArea____".stJam____.stData, + stInOutJamEntr2 := "DB_JamArea____".stJam____.stData, // TODO(E-Planung) arInOutJamExit2 := "DB_JamArea____".stJam____.arCarrier, // TODO(E-Planung) - Staubereich J0040 vor TRO01 - stInOutJamExit2 := "DB_JamArea____".stJam____.stData, + stInOutJamExit2 := "DB_JamArea____".stJam____.stData, // TODO(E-Planung) arInOutJamExit3 := "DB_JamArea____".stJam____.arCarrier, // TODO(E-Planung) - Staubereich J0012 vor TRO02 - stInOutJamExit3 := "DB_JamArea____".stJam____.stData, + stInOutJamExit3 := "DB_JamArea____".stJam____.stData, // TODO(E-Planung) arInOutJamExit4 := "DB_JamArea____".stJam____.arCarrier, // TODO(E-Planung) - Staubereich J0058 vor TRO11 - stInOutJamExit4 := "DB_JamArea____".stJam____.stData, + stInOutJamExit4 := "DB_JamArea____".stJam____.stData, // TODO(E-Planung) xOutStopper1 => "MB____", // TODO(E-Planung) xOutStopper2 => "MB____", // TODO(E-Planung) xOutSw1ExTo3 => "MB____", // TODO(E-Planung) @@ -590,14 +610,23 @@ REGION TRO10 (2Sep2Swi) Sep 0005, 0036 stInOutHMI := "DB_Interface_HMI".stTRO.TRO10, nOutStateLast => "DB_GLOB_TroState".arTroState["cMainTro____"]); // TODO(E-Planung) - REGION Direction - "FC_Direction"(nInSwitchNo := "cSwi_____", // TODO(E-Planung) - nOutDirection => #TRO10.nInDirection1, - InOutCarrier := "DB_JamArea____".stJam____.arCarrier[1]); + "bx____-TriggerEnable" := #arCognexInterface["cScanner____"].xOutCamTriggerEnable; // TODO(E-Planung) + "bx____-Trigger" := #arCognexInterface["cScanner____"].xOutCamTrigger; // TODO(E-Planung) + "bx____-ResultsAck" := #arCognexInterface["cScanner____"].xOutCamResultsAck; // TODO(E-Planung) - "FC_Direction"(nInSwitchNo := "cSwi_____", // TODO(E-Planung) + "bx____-TriggerEnable" := #arCognexInterface["cScanner____"].xOutCamTriggerEnable; // TODO(E-Planung) + "bx____-Trigger" := #arCognexInterface["cScanner____"].xOutCamTrigger; // TODO(E-Planung) + "bx____-ResultsAck" := #arCognexInterface["cScanner____"].xOutCamResultsAck; // TODO(E-Planung) + + REGION Direction + "FC_Direction"(nInSwitchNo := "cSwi_____", // TODO(E-Planung) + nOutDirection => #TRO10.nInDirection1, + InOutCarrier := "DB_JamArea____".stJam____.arCarrier[1]); // TODO(E-Planung) + + "FC_Direction"(nInSwitchNo := "cSwi_____", // TODO(E-Planung) nOutDirection => #TRO10.nInDirection2, - InOutCarrier := "DB_JamArea____".stJam____.arCarrier[1]); + InOutCarrier := "DB_JamArea____".stJam____.arCarrier[1]); // TODO(E-Planung) + END_REGION END_REGION diff --git a/tests/test_scl_skeleton_golden.py b/tests/test_scl_skeleton_golden.py index e9f25fd..afe275b 100644 --- a/tests/test_scl_skeleton_golden.py +++ b/tests/test_scl_skeleton_golden.py @@ -17,6 +17,7 @@ Diff pruefen, dann die Referenzen neu schreiben mit import os import re +import shutil from pathlib import Path import pytest @@ -101,7 +102,7 @@ def test_cli_schreibt_referenz(name: str, tmp_path: Path, monkeypatch) -> None: def test_cli_templates_und_strict(tmp_path: Path, monkeypatch) -> None: """--templates schreibt die Template-Referenz; --strict bricht ab, solange - ein FB-Typ der Anlage (mubea: u. a. 2Sep2Swi) kein Template hat.""" + ein FB-Typ der Anlage kein Template hat (hier: Template-Ordner ohne 2Sep2Swi).""" if _aktualisieren(): pytest.skip("Referenzen werden nur ueber die render-Tests geschrieben") monkeypatch.setenv("SKEL_RESULTS", str(tmp_path)) @@ -113,7 +114,11 @@ def test_cli_templates_und_strict(tmp_path: Path, monkeypatch) -> None: assert _maskiert(ist) == soll (tmp_path / "mubea_FB_Main.scl").unlink() - assert scl_skeleton.main(["--json", json_file, "--templates", "--strict"]) == 1 + ohne_2sep2swi = tmp_path / "templates" + shutil.copytree(scl_skeleton.TEMPLATE_DIR, ohne_2sep2swi) + (ohne_2sep2swi / "FB_ILS_MTRO_2Sep2Swi.scl.j2").unlink() + assert scl_skeleton.main(["--json", json_file, "--templates", str(ohne_2sep2swi), + "--strict"]) == 1 assert not (tmp_path / "mubea_FB_Main.scl").exists() assert scl_skeleton.main(["--json", json_file, "--templates",