Dieser Post setzt den sechsundzwanzigsten Teil fort. C4 ist ein guter Ausgangspunkt — aber viele Domänen haben eigene Konzepte die sich in Software System, Container und Component nicht sauber abbilden. AUTOSAR hat SWCs, Ports und Runnables. Embedded-Hardware hat MCUs, Peripherals und Busse. Bausteinsicht lässt sich auf diese Sprachen erweitern.

Neue Elementtypen in specification definieren

Jeder neue Elementtyp wird in specification.elements deklariert:

{
  "specification": {
    "elements": {
      "system":      { "notation": "Software System", "container": true },
      "container":   { "notation": "Container" },

      "swc":         { "notation": "Software Component", "container": true },
      "port":        { "notation": "Port" },
      "runnable":    { "notation": "Runnable Entity" },
      "bsw":         { "notation": "Basic Software Module" },

      "mcu":         { "notation": "Microcontroller", "container": true },
      "peripheral":  { "notation": "Peripheral" },
      "bus":         { "notation": "Communication Bus" }
    },
    "relationships": {
      "provides":    { "notation": "provides" },
      "requires":    { "notation": "requires" },
      "triggers":    { "notation": "triggers" },
      "mapped-to":   { "notation": "mapped to" }
    }
  }
}

container: true bedeutet dass der Typ Kind-Elemente haben kann. notation ist der Label-Text der in draw.io unter dem Shape erscheint.

Ein AUTOSAR-Modell

{
  "model": {
    "ecu": {
      "kind": "mcu", "title": "ECU — AM335x",
      "children": {
        "eth-driver": {
          "kind": "bsw", "title": "EthIf Driver",
          "children": {
            "eth-rx": { "kind": "port", "title": "RxIndication" },
            "eth-tx": { "kind": "port", "title": "TxConfirmation" }
          }
        },
        "ethtrcv-drv": {
          "kind": "swc", "title": "EthTrcv Driver",
          "children": {
            "mdio-port": { "kind": "port", "title": "MDIO Interface" },
            "ctrl-port": { "kind": "port", "title": "Control Port" }
          }
        },
        "phy-init":   { "kind": "runnable", "title": "EthTrcv_Init" },
        "phy-setmode":{ "kind": "runnable", "title": "EthTrcv_SetTransceiverMode" }
      }
    },
    "phy-chip": { "kind": "peripheral", "title": "PHY TJA1100" },
    "mdio-bus": { "kind": "bus", "title": "MDIO Bus" }
  }
}

Die Relationships zwischen Ports nutzen die eigenen Typen:

{
  "relationships": [
    { "from": "ecu.ethtrcv-drv.mdio-port", "to": "mdio-bus",  "kind": "provides" },
    { "from": "mdio-bus",                  "to": "phy-chip",   "kind": "provides" },
    { "from": "ecu.phy-init",              "to": "phy-chip",   "kind": "triggers" },
    { "from": "ecu.ethtrcv-drv",           "to": "ecu.eth-driver", "kind": "requires" }
  ]
}

Shapes in draw.io anpassen

Bausteinsicht rendert jeden Elementtyp mit einem Standard-Shape (Rechteck). Eigene Shapes kommen über zwei Wege:

Style in specification.elements

Der einfachste Weg — Style direkt in der Spezifikation:

{
  "specification": {
    "elements": {
      "mcu": {
        "notation": "Microcontroller",
        "container": true,
        "style": {
          "shape":       "mxgraph.cisco.computers_and_peripherals.pc",
          "fillColor":   "#1ba1e2",
          "strokeColor": "#006EAF",
          "fontColor":   "#ffffff"
        }
      },
      "peripheral": {
        "notation": "Peripheral",
        "style": {
          "shape":       "mxgraph.cisco.computers_and_peripherals.generic_processor",
          "fillColor":   "#d5e8d4",
          "strokeColor": "#82b366"
        }
      },
      "bus": {
        "notation": "Communication Bus",
        "style": {
          "shape":       "mxgraph.cisco.network_management.generic_manageable_hub",
          "fillColor":   "#fff2cc",
          "strokeColor": "#d6b656"
        }
      }
    }
  }
}

Die Shape-Namen kommen aus der draw.io Shape-Library — im draw.io-Editor ein Shape suchen, Rechtsklick → "Edit Style" zeigt den Namen.

Tags für visuelle Codierung

Wenn Shapes zu aufwändig sind, reicht oft ein Tag mit Farbe (→ Teil 23):

{
  "specification": {
    "tags": [
      { "id": "autosar-ap", "description": "AUTOSAR Adaptive Platform",
        "style": { "fillColor": "#dae8fc", "strokeColor": "#6c8ebf" } },
      { "id": "autosar-cp", "description": "AUTOSAR Classic Platform",
        "style": { "fillColor": "#d5e8d4", "strokeColor": "#82b366" } },
      { "id": "hardware",   "description": "Hardware-Element",
        "style": { "fillColor": "#ffe6cc", "strokeColor": "#d6b656" } }
    ]
  }
}

Elemente bekommen dann "tags": ["autosar-cp"] und werden automatisch in der richtigen Farbe dargestellt.

Grenzen der Custom Notation

Was Bausteinsicht heute nicht unterstützt:

  • Eigene Validation-Regeln für neue Typen (z.B. "jede SWC muss mindestens einen Port haben") — das muss extern geprüft werden

  • Typabhängige Beziehungsregeln (z.B. "Port darf nur zu Bus verbunden werden, nicht zu System") — validate prüft nur ob IDs existieren, nicht ob Typen zusammenpassen

  • Hierarchieregeln (z.B. "Runnable nur innerhalb SWC") — container: true erlaubt beliebige Kinder-Typen

Für diese Prüfungen kann man bausteinsicht export-table --format json verwenden und die Ausgabe in einem separaten Script validieren.

Eine vollständige Domain-Notation: Embedded-Hardware

{
  "specification": {
    "elements": {
      "board":      { "notation": "PCB",           "container": true,
                      "style": { "fillColor": "#1ba1e2", "fontColor": "#ffffff" } },
      "mcu":        { "notation": "MCU",           "container": true,
                      "style": { "fillColor": "#0e6655" , "fontColor": "#ffffff" } },
      "peripheral": { "notation": "Peripheral",
                      "style": { "fillColor": "#d5e8d4" } },
      "memory":     { "notation": "Memory",
                      "style": { "fillColor": "#fff2cc" } },
      "bus":        { "notation": "Bus",
                      "style": { "shape": "mxgraph.cisco.network_management.generic_manageable_hub" } },
      "connector":  { "notation": "Connector",
                      "style": { "shape": "rhombus" } }
    },
    "relationships": {
      "connected-via": { "notation": "via" },
      "controls":      { "notation": "controls" },
      "mapped-to":     { "notation": "mapped to" }
    }
  }
}

Damit lassen sich Hardware-Architekturen mit denselben Werkzeugen beschreiben wie Software-Architekturen — sync, validate, diff, export funktionieren identisch.

Beispiel-Modell

Das Beispiel für diesen Teil (benutzerdefinierte Notationen: Browser, Hexagon, Gear, Queue, Cylinder, Cloud) liegt unter teil_27.jsonc.

So sieht das Ergebnis in draw.io aus (bausteinsicht sync):

Das draw.io-File dafür findest du hier: teil_27.drawio

Generierte PNG-Dateien via bausteinsicht export --image-format png:

containers
context

Generierte PlantUML-Diagramme via bausteinsicht export-diagram:

Diagram
Diagram

Weiter geht es mit Performance

Eigene Notationen führen oft zu größeren Modellen — mehr Typen, mehr Elemente. Im nächsten Teil geht es darum wie man mit 50+ Elementen umgeht ohne die Übersicht zu verlieren.

Offizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org