# JSON Layout-Konfiguration fuer HundM_Fortna SCL-Code-Generierung

## Kontext

Die 5 SPS-Konfigurationen (UH01-UH05) enthalten tausende Zeilen repetitiven SCL-Code in `FB_Main`, `FB_CallSensors`, `FC_Direction` und `FC_Call_Jams`. Dieser Code folgt festen Mustern pro Element-Typ und unterscheidet sich nur in den konkreten Parametern (Adressen, Sensor-IDs, TRO-Nummern, Timing-Werte). Eine JSON-Konfigurationsdatei koennte als **Single Source of Truth** dienen, aus der der gesamte topologie-spezifische SCL-Code generiert wird.

## Identifizierte Element-Typen (aus FB_Main UH01)

| Typ | FB-Typ | Anzahl UH01 | Kennzeichen |
|---|---|---|---|
| Conveyor/Carousel | `FB_Conveyor` | 13 | Motor, Grid-Sensor, Schaltschrank |
| TRO 1Sep | `FB_ILS_MTRO_1Sep` | ~15 | 1 Separator, Entry/Exit Jam |
| TRO 1Sep + Scanner | `FB_ILS_MTRO_1Sep` | 5 | + Cognex Barcode-Reader |
| TRO 1Sep1Swi | `FB_ILS_MTRO_1Sep1Swi` | 4 | + Switch mit Direction-Logik |
| TRO 1Sep SSCC | `FB_ILS_MTRO_1Sep_SSCC` | 2 | + SSCC-Scanner + DReqM Telegramm |
| TRO Vario | `FB_ILS_MTRO_Vario` | 9 | Ketten-/Variofuerderer |
| EmptyCarrBuffer | `FB_EmptyCarrBuffer` | 2 | Mehrzeiliger Puffer + Weichen |
| LoadingBoom | `FB_LoadingBoom_INBOUND` | 2 | Komplex: Boom, Fuss, Stopper, Tilt, Distance |
| Sensor | `FB_SensorInput` | ~200 | Pro physischem Sensor |

---

## Vorschlag fuer eine standardisierte TRO-Liste

### Uebersicht aller TROs nach Steuerung

Insgesamt wurden **237 TROs** ueber alle 5 Steuerungen identifiziert. Die TRO-IDs folgen dem Schema `TRO<UH-Nr><lfd>` (z.B. TRO100-TRO134 fuer UH01).

| Steuerung | TRO-Bereich | Anzahl TROs | Schwerpunkt |
|---|---|---|---|
| UH01 | TRO100-TRO134 | 21 | Inbound, Loading Booms, SSCC-Scanner, Empty Carrier Buffer |
| UH02 | TRO200-TRO275 | 76 | 3x PinStore-Bloecke (automatisiertes Lager) |
| UH03 | TRO301-TRO386 | 84 | 3x PinStore-Bloecke (2.1, 2.2, 2.3) + F2H |
| UH04 | TRO402-TRO424 | 24 | 3x Work Stations (manuelle Arbeitsplaetze) |
| UH05 | TRO500-TRO531 | 32 | Laengenmessung + Verteilsystem |

### FB-Typ-Verteilung ueber alle Steuerungen

| FB-Typ | Beschreibung | UH01 | UH02 | UH03 | UH04 | UH05 | Gesamt |
|---|---|---|---|---|---|---|---|
| `FB_ILS_MTRO_1Sep` | Standard-Separator | ~15 | ~20 | ~25 | ~8 | ~10 | ~78 |
| `FB_ILS_MTRO_Vario` | Kettenfoerderer (variabel) | 9 | ~15 | ~18 | 4 | ~12 | ~58 |
| `FB_ILS_MTRO_1Sep1Swi` | Separator + 1 Weiche | 4 | ~8 | ~12 | 3 | 5 | ~32 |
| `FB_ILS_MTRO_1Sep2Swi` | Separator + 2 Weichen | 0 | ~5 | ~6 | 0 | 0 | ~11 |
| `FB_ILS_MTRO_PinStore_Auto` | Automatisches Pin-Lager | 0 | ~20 | ~18 | 0 | 0 | ~38 |
| `FB_ILS_MTRO_1Sep_SSCC` | SSCC-Barcode-Scanner | 2 | 0 | 0 | 0 | 0 | 2 |
| `FB_ILS_MTRO_Vario_workStation` | Manueller Arbeitsplatz | 0 | 0 | 0 | 3 | 0 | 3 |
| `FB_EmptyCarrBuffer` | Leertablar-Puffer | 2 | 0 | 0 | 0 | 0 | 2 |

### Detaillierte TRO-Liste UH01

| TRO | FB-Typ | Scanner | Switch | Prio | Besonderheit |
|---|---|---|---|---|---|
| TRO100 | 1Sep | - | - | releaseOk | Eingang Kreisel |
| TRO101_IN | 1Sep | - | - | releaseOk | Eingang Empty Buffer rechts |
| TRO101 | EmptyCarrBuffer | - | - | Manager | 5-Zeilen Leertablar-Puffer rechts |
| TRO102_IN | 1Sep | - | - | releaseOk | Eingang Empty Buffer links |
| TRO102 | EmptyCarrBuffer | - | - | Manager | 5-Zeilen Leertablar-Puffer links |
| TRO103 | 1Sep | - | - | releaseOk | Zufahrt Loading Boom 1 |
| TRO104 | 1Sep | BX1103 | - | releaseOk | Stopper vor Boom 1 + Barcode |
| TRO105 | 1Sep_SSCC | BX1104 + BX1107 | - | releaseOk | SSCC-Scanner Boom 1 + WCS DReqM |
| TRO106 | 1Sep | - | - | Manager | Abfahrt Boom 1 |
| TRO107 | 1Sep1Swi | - | cSwi107.1 | Dir2 Manager | Weiche Boom 1 (LS / Clearing) |
| TRO108 | 1Sep | - | - | releaseOk | Zufahrt Loading Boom 2 |
| TRO109 | 1Sep | BX1105 | - | releaseOk | Stopper vor Boom 2 + Barcode |
| TRO110 | 1Sep_SSCC | BX1106 + BX1108 | - | releaseOk | SSCC-Scanner Boom 2 + WCS DReqM |
| TRO111 | 1Sep | - | - | Manager | Abfahrt Boom 2 |
| TRO112 | 1Sep1Swi | - | cSwi112.1 | Dir2 Manager | Weiche Boom 2 (LS / Clearing) |
| TRO113 | 1Sep | BX1101 | - | releaseOk | RFID + Barcode vor Ausfahrt |
| TRO114 | 1Sep1Swi | - | cSwi114.1 | - | Weiche Inbound Out / Clearing |
| TRO115 | Vario | - | - | releaseOk | Loaded to Storage (Kette) |
| TRO116 | 1Sep | - | - | releaseOk | Separator vor Clearing |
| TRO117 | 1Sep | BX1100 | - | Manager | Clearing Station + Barcode |
| TRO120 | Vario | - | - | releaseOk | Highway Vario |
| TRO121 | Vario | - | - | releaseOk | Highway Vario |
| TRO122 | 1Sep | - | - | releaseOk | Highway Separator |
| TRO123 | Vario | - | - | releaseOk | Highway Vario |
| TRO124 | 1Sep1Swi | - | cSwi124.1 | Manager | Weiche Highway (Storage / Inbound) |
| TRO125 | 1Sep | - | - | Manager | Highway Separator |
| TRO126 | Vario | - | - | releaseOk | Empty to Storage (Kette) |
| TRO127 | Vario | - | - | releaseOk | Empty to Inbound (Kette) |
| TRO128 | Vario | - | - | releaseOk | Loaded to AMR (Kette) |
| TRO129 | 1Sep | - | - | Manager | Highway Separator |
| TRO130 | 1Sep | - | - | Manager | Highway Separator |
| TRO131 | Vario | - | - | releaseOk | Highway Vario |
| TRO132 | 1Sep | - | - | releaseOk | Highway Separator |
| TRO133 | Vario | - | - | releaseOk | Highway Vario |
| TRO134 | Vario | - | - | releaseOk | Highway Vario |

### Spezial-Elemente je Steuerung

| Feature | UH01 | UH02 | UH03 | UH04 | UH05 |
|---|---|---|---|---|---|
| SSCC-Scanner | TRO105, TRO110 | - | - | - | - |
| Cognex Barcode | BX1100-BX1108 | - | - | BX4103 | BX5101 |
| PinStore (autom. Lager) | - | 3 Bloecke | 3 Bloecke (2.1-2.3) | - | - |
| Work Station (manuell) | - | - | - | TRO421-423 | - |
| Laengenmessung | - | - | - | - | TRO500 |
| Empty Carrier Buffer | TRO101, TRO102 | - | - | - | - |
| Loading Boom | Boom1, Boom2 | - | - | - | - |
| Borner (Einschleusung) | TRO101, TRO102 | TRO200, 240, 270, 272 | - | - | TRO500, 502 |
| F2H (Floor-to-Hub) | - | - | TRO308, 383, 386 | - | - |

### Namenskonvention fuer standardisierte JSON-Konfiguration

Um eine einheitliche JSON pro Steuerung zu erzeugen, wird folgendes Schema empfohlen:

```
TRO-ID:          TRO<UH-Nr * 100 + lfd>    z.B. TRO115, TRO207, TRO315
Separator-Nr:    cSep<TRO-ID>.1             z.B. cSep115.1
Switch-Nr:       cSwi<TRO-ID>.1             z.B. cSwi107.1
MainTroNo:       cMainTro<TRO-ID>           z.B. cMainTro115
JamArea-DB:      DB_JamArea<4-stellig>      z.B. DB_JamArea0107
Scanner-ID:      cScannerBX<4-stellig>      z.B. cScannerBX1104
HMI-Pfad:        DB_Interface_HMI.stTRO.TRO<ID>
```

---

## Vorgeschlagene JSON-Struktur

### 1. Projekt-Header & SPS-Konfiguration

```json
{
  "$schema": "hmf-layout-v1.schema.json",
  "version": "1.0",
  "project": "HundM_Fortna",

  "plc": {
    "id": "UH01",
    "configName": "=A01+UH01-KF00",
    "plcId": "cPLCID",
    "connectionIdWCSBL": 10
  },

  "controlUnits": [
    {
      "id": "OF1",
      "safetySignal": "DB_InterfaceSafety.stFromSafety.EStopMainOF1.Q",
      "mainContactors": [
        "DB_InterfaceSafety.stFromSafety.stMainContactorsUH01.Q",
        "DB_InterfaceSafety.stFromSafety.stMainContactorsUC0110.Q",
        "DB_InterfaceSafety.stFromSafety.stMainContactorsUC0111.Q"
      ],
      "machineState": "DB_MachineGlobal.stStateMainOF1"
    },
    {
      "id": "OF2",
      "safetySignal": "DB_InterfaceSafety.stFromSafety.EStopMainOF2.Q",
      "mainContactors": [
        "DB_InterfaceSafety.stFromSafety.stMainContactorsUC011.Q"
      ],
      "machineState": "DB_MachineGlobal.stStateMainOF2"
    }
  ]
}
```

### 2. Sensoren (erzeugt `FB_CallSensors`)

```json
"sensors": [
  {
    "id": "BG0280",
    "constant": "cInBG0280",
    "hwInput": "BG0280",
    "controlUnit": "OF1",
    "comment": "TRO104 Sep Sensor"
  },
  {
    "id": "BG0282",
    "constant": "cInBG0282",
    "hwInput": "BG0282",
    "controlUnit": "OF1",
    "comment": "LoadingBoom1 Stopper1"
  }
]
```

### 3. Conveyors / Carousels (erzeugt REGION Conveyor in `FB_Main`)

#### Standard-Conveyor (Carousel mit Grid-Sensor)

```json
"conveyors": [
  {
    "id": "Carousel0101",
    "instanceName": "fbCarousel0101",
    "comment": "Eingangskreisel",
    "controlUnit": "OF1",
    "settings": {
      "energySafeTime": "cTimeEnergySafe",
      "gridActive": true,
      "motorProtectName": "FC0060",
      "gridSenName": "BG3347"
    },
    "io": {
      "enabled": "cTodoTRUE",
      "gridSensor": "cInBG3347",
      "gridQuit": ["SF0031", "SF0002"],
      "motorProtection": "FC0060",
      "powerContactor": "MA0060",
      "hmiPath": "DB_Interface_HMI.stConveyors.stCarousel.stCar0101"
    },
    "requestRunSources": [
      { "type": "startupCounter", "value": 100 },
      { "type": "restart" },
      { "type": "troCarouselReq", "tro": "TRO100" },
      { "type": "troCarouselReq", "tro": "TRO101_IN" },
      { "type": "troCarouselReq", "tro": "TRO102_IN" }
    ]
  }
]
```

#### Buersten-Conveyor (Subtype brush)

```json
{
  "id": "Conveyor4103_B",
  "instanceName": "fbConveyor4103_B",
  "comment": "Buersten Highway Loaded to Storage",
  "controlUnit": "OF2",
  "subtype": "brush",
  "settings": {
    "energySafeTime": "T#90s",
    "gridActive": false,
    "motorProtectName": "FC0152"
  },
  "io": {
    "motorProtection": "FC0152",
    "powerContactor": "MA0152",
    "hmiPath": "DB_Interface_HMI.stConveyors.stCarousel.stCar4103_B"
  },
  "brushConfig": {
    "triggerSensor": "cInBG3140",
    "jamSensor": "cInBG3143",
    "fullSensor": "cInBG3142",
    "taktTime": "T#1s"
  }
}
```

### 4. TROs (Transfer Route Objects)

#### TRO 1Sep — Standard-Separator

```json
"tros": [
  {
    "id": "TRO100",
    "type": "1Sep",
    "fbType": "FB_ILS_MTRO_1Sep",
    "mainTroNo": "cMainTro100",
    "controlUnit": "OF1",
    "comment": "Eingang Kreisel",
    "separator": {
      "no": "cSep100.1",
      "delayToNextItem": "TimeForSepWaiting_Short",
      "trailingTime": "T#600ms",
      "handlingTime": "T#200ms",
      "jamTime": "TimeForSepJam",
      "senFree": "T#1500ms",
      "senWait": "T#4000ms",
      "plugged": {
        "jam": true,
        "part": false,
        "scanner": false
      },
      "sensorInSep": "cInBG3242"
    },
    "sensorJam2": "cInBG3243",
    "priority": { "releaseOk": true },
    "call": {
      "carouselRun": "fbCarousel0101.xOutConveyorFullSpeed",
      "release": "DB_TRO_TEST.TRO100"
    },
    "jamAreas": {
      "entry": "DB_JamArea0100.stJam0100_1",
      "exit": "DB_JamArea0101.stJam0101_1"
    },
    "outputs": {
      "stopper1": "MB3242"
    },
    "hmi": "DB_Interface_HMI.stTRO.TRO100"
  }
]
```

#### TRO 1Sep1Swi — Separator + Switch mit Direction-Logik

```json
{
  "id": "TRO107",
  "type": "1Sep1Swi",
  "fbType": "FB_ILS_MTRO_1Sep1Swi",
  "mainTroNo": "cMainTro107",
  "controlUnit": "OF1",
  "comment": "Switch Boom 1",
  "separator": {
    "no": "cSep107.1",
    "delayToNextItem": "TimeForSepWaiting_Short",
    "trailingTime": "T#100ms",
    "handlingTime": "T#50ms",
    "jamTime": "TimeForSepJam",
    "plugged": { "jam": true, "part": false, "scanner": false },
    "sensorInSep": "cInBG3306"
  },
  "sensorJam2": "cInBG3305",
  "sensorJam3": "cInBG3330",
  "switch": {
    "no": "cSwi107.1",
    "pluggedExSen3": false,
    "pluggedExSen4": false,
    "nTo1Destinations": 3
  },
  "settings": {
    "prioDir2": true
  },
  "priority": {
    "managerDir2In": "DB_Prozessdaten.stPriorityManager.udt_TRO107.TroIn",
    "managerDir2Out": "DB_Prozessdaten.stPriorityManager.udt_TRO107.TroOut"
  },
  "call": {
    "carouselRun1": "fbCarousel0102.xOutConveyorFullSpeed",
    "release": "true"
  },
  "jamAreas": {
    "entry": "DB_JamArea0102.stJam0102_1",
    "exit2": "DB_JamArea0103.stJam0103_1",
    "exit3": "DB_JamArea0102.stJam0102_2"
  },
  "outputs": {
    "stopper1": "MB3306",
    "sw1ExTo3": "MB3304"
  },
  "hmi": "DB_Interface_HMI.stTRO.TRO107",
  "direction": {
    "switchNo": "cSwi107.1",
    "carrierSource": "DB_JamArea0102.stJam0102_1.arCarrier[1]"
  }
}
```

#### TRO Vario — Kettenfoerderer

```json
{
  "id": "TRO115",
  "type": "Vario",
  "fbType": "FB_ILS_MTRO_Vario",
  "mainTroNo": "cMainTro115",
  "controlUnit": "OF1",
  "comment": "Loaded To Storage Vario",
  "separator": {
    "no": "cSep115.1",
    "delayToNextItem": "TimeForSepWaiting_Short",
    "trailingTime": "T#800ms",
    "handlingTime": "T#300ms",
    "jamTime": "TimeForSepJam",
    "senFree": "T#2000ms",
    "senWait": "T#5000ms",
    "plugged": { "jam": false, "part": false, "scanner": false },
    "sensorInSep": "cInBG3025"
  },
  "vario": {
    "continousEmptying": false,
    "waitForJog": "T#300ms",
    "convEmpty": "T#45000ms",
    "countCarrier": 1,
    "waitForStop": "T#3s",
    "carrierInPosDelay": "T#1200ms",
    "carrierInPosEdgeDelay": "T#100ms",
    "rasterHigh": "T#5s",
    "rasterLow": "T#5s",
    "jamSenDelayActive": true,
    "jamSenDelay": "T#2s",
    "sensors": {
      "carrInPos": "cInBG3026",
      "finger": "cInBG3027",
      "lastPos": "cInBG3000",
      "jam": "cInBG3001"
    }
  },
  "settings": { "isBorner": true },
  "priority": { "releaseOk": true },
  "call": {
    "motorProtection": "FC0145",
    "automatic": "#t_Automatik_OF1 AND SF0120",
    "errorQuit": "SF0002",
    "release": "DB_TRO_TEST.TRO115"
  },
  "jamAreas": {
    "entry": "DB_JamArea4104.stJam4104_1",
    "finger": "DB_JamArea4103.stJam4103_1"
  },
  "outputs": {
    "stopper": "MB3025",
    "varioMotor": "MA0145"
  },
  "hmi": "DB_Interface_HMI.stTRO.TRO115"
}
```

#### TRO 1Sep_SSCC — SSCC-Scanner + WCS-Telegramm

```json
{
  "id": "TRO105",
  "type": "1Sep_SSCC",
  "fbType": "FB_ILS_MTRO_1Sep_SSCC",
  "mainTroNo": "cMainTro105",
  "controlUnit": "OF1",
  "comment": "SSCC Scanner Boom 1",
  "separator": {
    "no": "cSep105.1",
    "delayToNextItem": "TimeForSepWaiting_Short",
    "trailingTime": "T#600ms",
    "handlingTime": "T#200ms",
    "jamTime": "TimeForSepJam",
    "senFree": "T#1500ms",
    "senWait": "T#4000ms",
    "plugged": { "jam": true, "part": false, "scanner": true },
    "sensorInSep": "cInBG3280"
  },
  "sensorJam2": "cInBG3281",
  "scanner": {
    "id": "cScannerBX1104",
    "prefix": "bx1104",
    "hwResults": "BX1104~Ergebnisse_-_64_Bytes_1",
    "checkASCII": true,
    "timeout": "T#3000ms"
  },
  "ssccScanner": {
    "prefix": "bx1107",
    "hwResults": "BX1107~Ergebnisse_-_64_Bytes_1",
    "checkASCII": true,
    "timeout": "T#3s",
    "sensorEndMeasurement": "cInBG3281"
  },
  "priority": { "releaseOk": true },
  "call": {
    "carouselRun": "true",
    "release": "FB_CommunicationWCSBL_DB.fbTeleHandler.xOutConnectionActive OR IBN.xFahrenOhneTcpPartner"
  },
  "jamAreas": {
    "entry": "DB_JamArea0104.stJam0104_3",
    "exit": "DB_JamArea0106.stJam0106_2"
  },
  "outputs": { "stopper1": "MB3280" },
  "hmi": "DB_Interface_HMI.stTRO.TRO105",
  "correction": {
    "station": 0,
    "carrierExpect": "DB_JamArea0104.stJam0104_3.arCarrier[1]"
  },
  "wcsTelegram": {
    "type": "DReqM",
    "decisionPoint": "cDP_DOCK_01",
    "dockDoor": "1",
    "ssccReq": true,
    "lengthReq": false,
    "dockDoorReq": true
  }
}
```

### 5. Loading Booms

```json
"loadingBooms": [
  {
    "id": "LoadingBoom1",
    "instanceName": "fbLoadingBoom1",
    "controlUnit": "OF1",
    "comment": "Ladeschleife 1",
    "relatedTro": "TRO104",
    "controls": {
      "btnReleaseMT1": "SF0305",
      "switchLoadingPos2": "SF0306",
      "btnBack": null,
      "btnForth": null,
      "btnReleaseMT2": "SF0332",
      "switchFootUp": null,
      "switchFootDown": null,
      "switchLightOnOff": "SF0041",
      "btnBoomActive": "SF0044",
      "btnReset": ["SF0043", "SF0002", "IBN.xQuit"],
      "switchFootManual": "SF0025"
    },
    "boom": {
      "motorProtection": ["FC0070", "FC0072"],
      "limitForth": "cInBG3343",
      "limitForthEmergency": "SF0051",
      "limitBack": "cInBG3344",
      "limitBackEmergency": "SF0050",
      "bumperOk": true
    },
    "foot": {
      "motorProtection": "FC0321",
      "limitUp": "SF0322",
      "limitDown": "SF0323"
    },
    "timings": {
      "boomInput": "T#5s",
      "wheelInput": "T#5s",
      "senWaitStopper1": "T#100ms",
      "waitAfterReleaseStopper1": "T#1200ms",
      "waitBeforeSwitchStopper2": "T#4000ms",
      "trailingStopper2": "T#150ms"
    },
    "tilt": {
      "analogInput": "wTiltSensorLS1",
      "hmiBasePath": "DB_Interface_HMI.stLoadingBoom.stDataBoom1"
    },
    "distance": {
      "analogInput": "wDistanceSensorLS1",
      "startSlow": 2510,
      "startFast": 2520,
      "hmiBasePath": "DB_Interface_HMI.stLoadingBoom.stDataBoom1"
    },
    "callSensors": {
      "sen2mThreshold": "cInBG0287",
      "senJamEntr": "cInBG0286",
      "senJamExit1": "cInBG0285",
      "senJamExit2": "cInBG3276",
      "senStopper1": "cInBG0282",
      "senStopper2": "cInBG0283"
    },
    "jamAreas": {
      "stopper": "DB_JamArea0104.stJam0104_2",
      "exit": "DB_JamArea0104.stJam0104_3"
    },
    "outputs": {
      "light": "QA0012",
      "boomActive": "PF0044",
      "ledMovement": "PF0287",
      "stopper1Clamp": "MB0282",
      "stopper1Finger": "MB0284",
      "stopper2": "MB0283",
      "boomForth1": "QA0071",
      "boomForth2": "QA0073",
      "boomBack1": "MA0070",
      "boomBack2": "MA0072",
      "footUp": "DQ0322",
      "footDown": "DQ0323",
      "footSpeed1": "DQ0324"
    },
    "hmi": "DB_Interface_HMI.stLoadingBoom.stDataBoom1"
  }
]
```

### 6. Empty Carrier Buffers (mehrzeiliger Puffer)

```json
"emptyCarrBuffers": [
  {
    "id": "TRO101",
    "instanceName": "TRO101",
    "mainTroNo": "cMainTro101",
    "controlUnit": "OF1",
    "comment": "Empty Buffer rechts",
    "numberOfLines": 5,
    "storageDb": "DB_JamBuffer101",
    "inTro": {
      "id": "TRO101_IN",
      "separator": {
        "no": 999,
        "delayToNextItem": "TimeForSepWaiting_Short",
        "trailingTime": "T#100ms",
        "handlingTime": "T#50ms",
        "jamTime": "TimeForSepJam",
        "sensorInSep": "cInBG3246"
      },
      "isBorner": true,
      "bornerDest": "cDestInboundLS",
      "carouselRun": "fbCarousel0101.xOutConveyorFullSpeed",
      "jamEntry": "DB_JamArea0101.stJam0101_1",
      "stopper": "MB3246",
      "hmi": "DB_Interface_HMI.stTRO.TRO101_In"
    },
    "separatorLines": [
      { "line": 1, "jamLength": 5,  "sensor": "cInBG3320", "handlingTime": "T#200ms", "trailingTime": "T#500ms", "senFree": "T#1500ms", "senWait": "T#3000ms" },
      { "line": 2, "jamLength": 7,  "sensor": "cInBG3321", "handlingTime": "T#200ms", "trailingTime": "T#500ms", "senFree": "T#1500ms", "senWait": "T#3000ms" },
      { "line": 3, "jamLength": 10, "sensor": "cInBG3322", "handlingTime": "T#200ms", "trailingTime": "T#500ms", "senFree": "T#1500ms", "senWait": "T#3000ms" },
      { "line": 4, "jamLength": 10, "sensor": "cInBG3323", "handlingTime": "T#200ms", "trailingTime": "T#500ms", "senFree": "T#1500ms", "senWait": "T#3000ms" },
      { "line": 5, "jamLength": 10, "sensor": "cInBG3324", "handlingTime": "T#200ms", "trailingTime": "T#500ms", "senFree": "T#1500ms", "senWait": "T#3000ms" }
    ],
    "jamSensors": ["cInBG3250", "cInBG3251", "cInBG3252", "cInBG3253", "cInBG3254"],
    "switchLineOutputs": ["MB3250", "MB3251", "MB3252", "MB3253", "MB3254"],
    "separatorStoreOutputs": ["MB3320", "MB3321", "MB3322", "MB3323", "MB3324"],
    "exitJam": "DB_JamArea0102.stJam0102_2",
    "exitSensor": "cInBG3330",
    "priority": {
      "managerIn": "DB_Prozessdaten.stPriorityManager.udt_TRO101.TroIn",
      "managerOut": "DB_Prozessdaten.stPriorityManager.udt_TRO101.TroOut"
    },
    "hmi": "DB_Interface_HMI.stTRO.TRO101"
  }
]
```

### 7. Routing / FC_Direction (erzeugt CASE-Statement)

```json
"routing": {
  "switches": [
    {
      "switchNo": "cSwi107.1",
      "comment": "Switch 107.1 Boom 1",
      "rules": [
        { "destination": "cDestInboundLS", "direction": 1, "comment": "LINKS - zu Ladeschleife" },
        { "destinations": ["cDestClearing", "cDestInboundOut", "cDestInboundLS_Extra"], "direction": 2, "comment": "RECHTS - Clearing/Inbound verlassen" }
      ],
      "default": 2
    },
    {
      "switchNo": "cSwi112.1",
      "comment": "Switch 112.1 Boom 2",
      "rules": [
        { "destinations": ["cDestInboundLS", "cDestInboundLS_Extra"], "direction": 1, "comment": "LINKS - zu Ladeschleife" },
        { "destinations": ["cDestClearing", "cDestInboundOut"], "direction": 2, "comment": "RECHTS - Clearing/Inbound verlassen" }
      ],
      "default": 2
    },
    {
      "switchNo": "cSwi114.1",
      "comment": "Switch 114.1",
      "rules": [
        { "destination": "cDestInboundOut", "direction": 1, "comment": "LINKS - Inbound verlassen" },
        { "destination": "cDestClearing", "direction": 2, "comment": "RECHTS - Clearing-Station" }
      ],
      "default": 0
    },
    {
      "switchNo": "cSwi124.1",
      "comment": "Switch 124.1",
      "rules": [
        { "destination": "cDestHighwayStorage", "direction": 1, "comment": "LINKS - zum Storage" },
        { "destination": 0, "direction": 2, "comment": "RECHTS - zum Inbound (Standard)" }
      ],
      "default": 2
    }
  ]
}
```

### 8. Jam Areas

```json
"jamAreas": [
  {
    "id": "JamArea0100",
    "db": "DB_JamArea0100",
    "slots": [
      { "name": "stJam0100_1", "capacity": 5 }
    ]
  },
  {
    "id": "JamArea0101",
    "db": "DB_JamArea0101",
    "slots": [
      { "name": "stJam0101_1", "capacity": 5 },
      { "name": "stJam0101_2", "capacity": 5 }
    ]
  },
  {
    "id": "JamArea0102",
    "db": "DB_JamArea0102",
    "slots": [
      { "name": "stJam0102_1", "capacity": 5 },
      { "name": "stJam0102_2", "capacity": 5 },
      { "name": "stJam0102_3", "capacity": 5 },
      { "name": "stJam0102_4", "capacity": 5 },
      { "name": "stJam0102_5", "capacity": 5 },
      { "name": "stJam0102_6", "capacity": 5 }
    ]
  }
]
```

### 9. Scanners (Cognex Barcode-Reader)

```json
"scanners": [
  {
    "id": "BX1100",
    "constant": "cScannerBX1100",
    "prefix": "bx1100",
    "hwResults": "BX1100~Ergebnisse_-_64_Bytes_1",
    "usedByTro": "TRO117"
  },
  {
    "id": "BX1101",
    "constant": "cScannerBX1101",
    "prefix": "bx1101",
    "hwResults": "BX1101~Ergebnisse_-_64_Bytes_1",
    "usedByTro": "TRO113"
  },
  {
    "id": "BX1103",
    "constant": "cScannerBX1103",
    "prefix": "bx1103",
    "hwResults": "BX1103~Ergebnisse_-_64_Bytes_1",
    "usedByTro": "TRO104"
  },
  {
    "id": "BX1104",
    "constant": "cScannerBX1104",
    "prefix": "bx1104",
    "hwResults": "BX1104~Ergebnisse_-_64_Bytes_1",
    "usedByTro": "TRO105"
  },
  {
    "id": "BX1105",
    "constant": "cScannerBX1105",
    "prefix": "bx1105",
    "hwResults": "BX1105~Ergebnisse_-_64_Bytes_1",
    "usedByTro": "TRO109"
  },
  {
    "id": "BX1106",
    "constant": "cScannerBX1106",
    "prefix": "bx1106",
    "hwResults": "BX1106~Ergebnisse_-_64_Bytes_1",
    "usedByTro": "TRO110"
  },
  {
    "id": "BX1107",
    "constant": "cScannerBX1107",
    "prefix": "bx1107",
    "hwResults": "BX1107~Ergebnisse_-_64_Bytes_1",
    "comment": "SSCC Scanner Boom 1",
    "usedByTro": "TRO105"
  },
  {
    "id": "BX1108",
    "constant": "cScannerBX1108",
    "prefix": "bx1108",
    "hwResults": "BX1108~Ergebnisse_-_64_Bytes_1",
    "comment": "SSCC Scanner Boom 2",
    "usedByTro": "TRO110"
  }
]
```

### 10. Sonderlogik — Hybrid-Ansatz (customCode fuer seltene Einzelfaelle)

Haeufige Muster werden als eigene JSON-Felder modelliert (scanner, ssccScanner, wcsTelegram, brushConfig, correction). Seltene Einzelfaelle werden als `customCode`-Bloecke eingebettet:

```json
{
  "id": "TRO117",
  "type": "1Sep",
  "fbType": "FB_ILS_MTRO_1Sep",
  "mainTroNo": "cMainTro117",
  "controlUnit": "OF1",
  "comment": "Clearing Station",
  "separator": {
    "no": "cSep117.1",
    "delayToNextItem": "TimeForSepWaiting_Short",
    "trailingTime": "T#100ms",
    "handlingTime": "T#50ms",
    "jamTime": "TimeForSepJam",
    "plugged": { "jam": true, "part": true, "scanner": true },
    "sensorInSep": "cInBG3300"
  },
  "sensorJam2": "cInBG3304",
  "scanner": {
    "id": "cScannerBX1100",
    "prefix": "bx1100",
    "hwResults": "BX1100~Ergebnisse_-_64_Bytes_1",
    "checkASCII": true,
    "timeout": "T#5s"
  },
  "correction": {
    "station": 0,
    "carrierExpect": "DB_JamArea0102.stJam0102_6.arCarrier[1]"
  },
  "customCode": {
    "beforeCall": [
      "#rTrig_ClarificationButton(CLK := \"SF0032\");"
    ],
    "releaseExpression": "#rTrig_ClarificationButton.Q",
    "afterCall": [
      "// Clearing-Station: Trolley loeschen",
      "IF NOT \"DB_Inputs\".Sensors[\"cInBG3300\"].xDirectSensor AND \"DB_Interface_HMI\".stClearingStation.xDeleteTrolley THEN",
      "    \"DB_JamArea0102\".stJam0102_6.arCarrier[1] := #stEmptyCarrier;",
      "    \"DB_Interface_HMI\".stClearingStation.xDeleteTrolley := FALSE;",
      "    #TRO117.nState := 100;",
      "END_IF;",
      "",
      "// Clearing-Station: Ladung loeschen",
      "IF NOT \"BG3301\" AND \"DB_Interface_HMI\".stClearingStation.xDeleteLoad THEN",
      "    \"DB_JamArea0102\".stJam0102_6.arCarrier[1].bStatus.%X1 := FALSE;",
      "    \"DB_Interface_HMI\".stClearingStation.xDeleteLoad := FALSE;",
      "END_IF;",
      "",
      "// HMI-Anzeige aktualisieren",
      "\"DB_Interface_HMI\".stClearingStation.stFirstCarrierInStation := \"DB_JamArea0102\".stJam0102_6.arCarrier[1];",
      "\"DB_Interface_HMI\".stClearingStation.xTrolleyInStation := \"DB_Inputs\".Sensors[\"cInBG3300\"].xDbncdSensor;"
    ]
  }
}
```

---

### 11. Connections — Physische Topologie (TRO-Verkettung)

Jede Verbindung beschreibt den Pfad: Quell-TRO + Exit-Slot → JamArea → Ziel-TRO + Entry-Slot.
Switch-Ausgaenge haben nummerierte Exit-Slots (`exit2`, `exit3`); normale TROs haben nur `exit`.

```json
"connections": [
  { "from": "TRO100",  "exitSlot": "exit",  "jamArea": "DB_JamArea0101.stJam0101_1", "to": "TRO101_IN", "entrySlot": "entry", "comment": "Eingang → Entry Buffer" },
  { "from": "TRO100",  "exitSlot": "exit",  "jamArea": "DB_JamArea0101.stJam0101_1", "to": "TRO101",    "entrySlot": "entry", "comment": "Parallel: direkt in EmptyBuffer" },
  { "from": "TRO101",  "exitSlot": "exit",  "jamArea": "DB_JamArea0102.stJam0102_2", "to": "TRO107",    "entrySlot": "entry", "comment": "EmptyBuffer → Switch Boom1" },
  { "from": "TRO102",  "exitSlot": "exit",  "jamArea": "DB_JamArea0102.stJam0102_1", "to": "TRO107",    "entrySlot": "entry" },
  { "from": "TRO107",  "exitSlot": "exit2", "jamArea": "DB_JamArea0103.stJam0103_1", "to": "TRO103",    "entrySlot": "entry", "direction": 1, "comment": "Dir1=LS1" },
  { "from": "TRO107",  "exitSlot": "exit3", "jamArea": "DB_JamArea0102.stJam0102_2", "to": "TRO112",    "entrySlot": "entry", "direction": 2, "comment": "Dir2=weiter" },
  { "from": "TRO103",  "exitSlot": "exit",  "jamArea": "DB_JamArea0104.stJam0104_1", "to": "TRO104",    "entrySlot": "entry" },
  { "from": "TRO104",  "exitSlot": "exit",  "jamArea": "DB_JamArea0104.stJam0104_2", "to": "LoadingBoom1", "entrySlot": "stopper" },
  { "from": "TRO106",  "exitSlot": "exit",  "jamArea": "DB_JamArea0102.stJam0102_2", "to": "TRO112",    "entrySlot": "entry", "comment": "LS1 Rueckleitung" },
  { "from": "TRO112",  "exitSlot": "exit2", "jamArea": "DB_JamArea0107.stJam0107_1", "to": "TRO108",    "entrySlot": "entry", "direction": 1, "comment": "Dir1=LS2" },
  { "from": "TRO112",  "exitSlot": "exit3", "jamArea": "DB_JamArea0102.stJam0102_3", "to": "TRO113",    "entrySlot": "entry", "direction": 2, "comment": "Dir2=Clearing" },
  { "from": "TRO111",  "exitSlot": "exit",  "jamArea": "DB_JamArea0102.stJam0102_3", "to": "TRO113",    "entrySlot": "entry", "comment": "LS2 Rueckleitung" },
  { "from": "TRO113",  "exitSlot": "exit",  "jamArea": "DB_JamArea0102.stJam0102_4", "to": "TRO114",    "entrySlot": "entry" },
  { "from": "TRO114",  "exitSlot": "exit2", "jamArea": "DB_JamArea4104.stJam4104_1", "to": null,         "entrySlot": null,    "direction": 1, "comment": "Dir1=InboundOut→WCS" },
  { "from": "TRO114",  "exitSlot": "exit3", "jamArea": "DB_JamArea0102.stJam0102_5", "to": "TRO116",    "entrySlot": "entry", "direction": 2, "comment": "Dir2=Clearing" }
]
```

**Mehrwert `connections`**:

- Topologie-Validierung: Generator prueft ob jede in `tros[].jamAreas` genannte JamArea auch in `connections` erscheint
- Topologie-Diagramme: Aus `connections` wird automatisch ein Mermaid-Flowchart erzeugt
- Cross-Config-Vergleich: `connections` von UH01 vs UH04 direkt vergleichbar

---

### 12. Destinations — Abstrakte Routing-Tabelle

Beschreibt pro Carrier-Ziel: welche Switches wie geschaltet werden, den vollstaendigen TRO-Pfad und die Endaktion.
Ermoeglicht automatische Generierung von `FC_Direction` ohne manuelles Pflegen von `routing.switches`.

```json
"destinations": [
  {
    "id": "cDestInboundLS",
    "constant": 100,
    "description": "Carrier in Ladeschleife beladen (Loading Station 1 oder 2)",
    "routes": [
      {
        "id": "route_LS1",
        "description": "Weg zur Loading Station 1 (Boom 1)",
        "switchDecisions": [
          { "tro": "TRO107", "switch": "cSwi107.1", "direction": 1 },
          { "tro": "TRO112", "switch": "cSwi112.1", "direction": 2 }
        ],
        "path": ["TRO107", "TRO103", "TRO104", "LoadingBoom1", "TRO105", "TRO106"],
        "terminal": { "type": "loadingBoom", "element": "LoadingBoom1" }
      },
      {
        "id": "route_LS2",
        "description": "Weg zur Loading Station 2 (Boom 2)",
        "switchDecisions": [
          { "tro": "TRO107", "switch": "cSwi107.1", "direction": 2 },
          { "tro": "TRO112", "switch": "cSwi112.1", "direction": 1 }
        ],
        "path": ["TRO107", "TRO112", "TRO108", "TRO109", "LoadingBoom2", "TRO110", "TRO111"],
        "terminal": { "type": "loadingBoom", "element": "LoadingBoom2" }
      }
    ],
    "wcsTelegram": { "type": "DReqM", "decisionPoints": ["cDP_DOCK_01", "cDP_DOCK_02"] }
  },
  {
    "id": "cDestClearing",
    "constant": 200,
    "description": "Carrier zur Clearing-/Error-Station",
    "routes": [
      {
        "id": "route_clearing",
        "switchDecisions": [
          { "tro": "TRO107", "switch": "cSwi107.1", "direction": 2 },
          { "tro": "TRO112", "switch": "cSwi112.1", "direction": 2 },
          { "tro": "TRO114", "switch": "cSwi114.1", "direction": 2 }
        ],
        "path": ["TRO107", "TRO112", "TRO113", "TRO114", "TRO116", "TRO117"],
        "terminal": { "type": "clearingStation", "element": "TRO117" }
      }
    ]
  },
  {
    "id": "cDestInboundOut",
    "constant": 300,
    "description": "Carrier verlaesst das Inbound-System",
    "routes": [
      {
        "id": "route_exit",
        "switchDecisions": [
          { "tro": "TRO114", "switch": "cSwi114.1", "direction": 1 }
        ],
        "path": ["TRO113", "TRO114"],
        "terminal": { "type": "wcsTelegram", "action": "cSTRAIGHT", "decisionPoint": "cDP_INBOUND_OUT" }
      }
    ]
  },
  {
    "id": "cDestHighwayStorage",
    "constant": 400,
    "description": "Carrier faehrt zum Storage ueber Highway",
    "routes": [
      {
        "id": "route_storage",
        "switchDecisions": [
          { "tro": "TRO124", "switch": "cSwi124.1", "direction": 1 }
        ],
        "path": ["TRO113", "TRO114", "TRO120", "TRO121", "TRO122", "TRO123", "TRO124"],
        "terminal": { "type": "wcsTelegram", "action": "cSTORAGE", "decisionPoint": "cDP_HIGHWAY" }
      }
    ]
  }
]
```

**Auswirkung auf bestehende Abschnitte**:

| Abschnitt | Auswirkung |
|---|---|
| `routing.switches[].rules` | Kann aus `destinations[].routes[].switchDecisions` abgeleitet werden (Single Source of Truth) |
| `tros[].jamAreas` | Bleibt explizit fuer Debugging; Generator validiert Konsistenz gegen `connections[]` |
| `FC_Direction` (generiert) | Wird kuenftig aus `destinations` statt aus `routing.switches` generiert |

**Mehrwert `destinations`**:

- `FC_Direction` auto-generieren: Switch-Regeln kommen direkt aus `switchDecisions`
- Dokumentation: vollstaendiger Carrier-Pfad pro Ziel als Planungsgrundlage
- Simulation: Carrier-Fluss kann ohne SPS per Graph-Traversal simuliert werden

---

## Welche SCL-Bausteine werden daraus generiert?

| Ziel-Baustein | Generiert aus JSON-Abschnitt |
|---|---|
| `FB_Main` VAR-Deklaration | `conveyors[]`, `tros[]`, `loadingBooms[]`, `emptyCarrBuffers[]` |
| `FB_Main` REGION Conveyor | `conveyors[]` — Settings + Call-Pattern je Subtype |
| `FB_Main` REGION TRO | `tros[]` — Separator-Settings + Call je fbType |
| `FB_Main` REGION LoadingBoom | `loadingBooms[]` — Controls/Boom/Foot/Call/Outputs |
| `FB_Main` REGION EmptyCarrBuffer | `emptyCarrBuffers[]` — Lines/Jams/Call |
| `FB_Main` REGION Reinitialisieren | alle `tros[].mainTroNo` + `emptyCarrBuffers[].mainTroNo` |
| `FB_CallSensors` | `sensors[]` — repetitiver Call-Block pro Sensor |
| `FC_Direction` | `routing.switches[]` — CASE-Statement |
| `FC_Call_Jams` | `jamAreas[]` — Jam-Aufrufe |
| `FC_CARR_GLOB_CORRECTION` | TROs mit `correction`-Feld |
| Konstanten-Tabelle | Alle `constant`-Felder — TIA-Konstantenliste |

---

## Vorteile

1. **Single Source of Truth**: Aenderung an einem Ort (JSON) statt in 5 verschiedenen 3000-9000 Zeilen SCL-Dateien
2. **Fehlerreduktion**: Kein Copy-Paste mehr zwischen UH01-UH05
3. **Review**: Topologie-Aenderungen sind als JSON-Diff lesbar
4. **Neues Projekt**: Nur neue JSON-Datei anlegen, Code wird generiert
5. **Validierung**: JSON-Schema kann Pflichtfelder, gueltige Typen etc. pruefen

---

## Sonderlogik-Behandlung (Hybrid-Ansatz)

| Muster | Haeufigkeit | Behandlung |
|---|---|---|
| Scanner + Correction | 5x pro UH | Eigene JSON-Felder (`scanner`, `correction`) |
| SSCC-Scanner + WCS-Telegramm | 2x pro UH | Eigene JSON-Felder (`ssccScanner`, `wcsTelegram`) |
| Buersten-Taktlogik | 4x in UH01 | Eigenes JSON-Feld (`brushConfig`) |
| Priority Manager | ~10x pro UH | Eigenes JSON-Feld (`priority`) |
| Clearing-Station (Delete-Buttons) | 1x in UH01 | `customCode.afterCall` |
| Laengenmessung DReqM | 1x in UH01/UH05 | `customCode.afterCall` |

---

## Offene Designentscheidungen

1. **Ausdruck-Sprache**: Felder wie `release` enthalten SCL-Ausdruecke (`#fbLoadingBoom1.xOutReady AND ...`). Diese werden als Strings durchgereicht.

2. **Generator**: Falls gewuenscht, Python + Jinja2-Templates als `bin/generate_scl.py` im Repository.

3. **JamArea-Kapazitaeten**: Koennten vollstaendig in die JSON aufgenommen werden, um auch die JamArea-DBs zu generieren.

4. **Topologie-Verbindungen**: Die JSON beschreibt aktuell jedes Element isoliert. Optional koennte ein `connections`-Abschnitt die Verkettung (TRO100 -> JamArea0101 -> TRO101_IN -> Buffer -> TRO101 -> JamArea0102 -> ...) explizit machen.