.. index:: Gerätetreiber; gemeinsames Verhalten, Geräte-API, Statuscode, ignore_bus Gemeinsames Gerätetreiber-Verhalten =================================== Messklassen und :doc:`MGraph ` sprechen nicht unmittelbar mit einem bestimmten Gerät, sondern mit der öffentlichen API seiner Gerätebasisklasse. Alle gepflegten Treiber derselben Gerätefamilie müssen sich nach außen gleich verhalten. Dadurch kann eine Konfiguration zwischen realem und virtuellem Gerät wechseln, ohne den Messablauf anzupassen. Diese Seite beschreibt die gemeinsamen Laufzeitregeln. Gerätespezifische Befehle stehen in der jeweiligen Treiberimplementierung; die vollständigen Signaturen sind in der :doc:`Treiber-API <../../api/drivers>` dokumentiert. Basisklasse bestimmt die Schnittstelle --------------------------------------- Ein konkreter Treiber erbt von der passenden Basisklasse, beispielsweise ``SIGNALGENERATOR``, ``RECEIVER``, ``POWERMETER``, ``FIELDPROBE`` oder ``AMPLIFIER``. Die Basisklasse legt fest: * Methodennamen und Signaturen; * Rückgabeform und Statusbehandlung; * Einheiten und Quantity-Typen; * Validierung gemeinsamer Parameter; * Fallbacks für Trigger- und Nonblocking-Betrieb; * das Konfigurationsschema der INI-Datei. Ein spezifischer Treiber darf zusätzliche gerätenahe Methoden anbieten. Eine geerbte öffentliche Methode darf er aber nicht mit anderer Signatur, Rückgabeform oder Bedeutung überschreiben. Nicht unterstützte Fähigkeiten werden entsprechend der Basisklasse eindeutig gemeldet und nicht durch einen scheinbar erfolgreichen Ersatz verdeckt. Status und Rückgabewerte ------------------------ ``0`` bezeichnet regulären Erfolg. Ein negativer Status bezeichnet einen Fehler. Positive Werte dürfen nur verwendet werden, wenn die betreffende Gerätefamilie ihre Bedeutung ausdrücklich definiert. Abfragemethoden liefern normalerweise ``(status, value)``. Aktionsmethoden liefern je nach Basisklasse entweder nur ``status`` oder ebenfalls ein Tupel, beispielsweise ``(status, tatsächlich_gesetzter_wert)``. Maßgeblich ist immer die Signatur der Basisklasse. Aufrufender Code darf die Rückgabeform nicht aus dem Methodennamen erraten. Treiber halten den letzten Status in ``self.error``. MGraph speichert Geräteergebnisse zusätzlich unter ``nodes[name]['ret']`` und Fehlerdetails unter ``nodes[name]['err']``. Ein negativer Originalstatus bleibt erhalten, auch wenn ein moderner Treiber keine historische ``GetLastError()``-Methode bereitstellt. Lebenszyklus und Busstrategie ----------------------------- Der typische Lebenszyklus ist: #. Treiberinstanz erzeugen; #. INI-Datei mit ``Init`` einlesen und gegebenenfalls den Bus öffnen; #. Frequenz, Kanal und Betriebszustand setzen; #. triggern und Daten lesen; #. HF abschalten und ``Quit`` ausführen. Der Konstruktor öffnet keine Hardwareverbindung. Auch ``MGraph.CreateDevices()`` erzeugt und verbindet nur Python-Objekte. Der reale Hardwarezugriff beginnt mit ``Init_Devices()`` beziehungsweise ``Init()``. Alle gepflegten Treiber verwenden: .. code-block:: python Init(ini=None, channel=None, ignore_bus=None) ``ignore_bus`` ist dreistufig: ``None`` Verwendet ``_default_ignore_bus`` der konkreten Klasse. Aktive Geräte öffnen normalerweise den Bus; passive und virtuelle Geräte ignorieren ihn. ``True`` Unterdrückt den Buszugriff ausdrücklich. Die Konfiguration darf dennoch eingelesen werden; geräteseitige Presets und Zustandswechsel unterbleiben. ``False`` Fordert den Buszugriff ausdrücklich an, sofern die Geräteart ihn unterstützt. Die aufgelöste Entscheidung steht in ``self.bus_ignored``. Ein konkreter aktiver Treiber prüft sie unmittelbar nach ``super().Init(...)`` und sendet ohne verfügbaren Bus keine Gerätebefehle. Aktive und inaktive Graphgeräte ------------------------------- ``EvaluateConditions(context=...)`` setzt den Aktivzustand von Knoten und Kanten. MGraph-Operationen wie ``Init_Devices()``, ``SetFreq_Devices()``, ``Trigger_Devices()``, ``Read()`` und ``Quit_Devices()`` berücksichtigen standardmäßig nur aktive Geräte. ``IgnoreInactive=False`` schließt inaktive Geräte ausdrücklich ein. Bei frequenzabhängigen Graphen wird die Condition mit einem expliziten Kontext ausgewertet. Vor einer Messung muss genau der erwartete Pfad aktiv sein. Die :doc:`DOT-Referenz <../configuration/dot>` beschreibt ``FREQUENCY_CONDITION_MAP`` und ``check_paths``; die :doc:`Pfadkorrektur-Referenz ` erklärt das Zusammenspiel mit Switches und S-Parametern. Frequenz, Trigger und Messdaten ------------------------------- Öffentliche Frequenzmethoden verwenden Hertz. Ungültige, nicht endliche oder außerhalb des unterstützten Bereichs liegende Werte werden vor einem Hardwarebefehl abgelehnt. Die konkrete Rückgabe von ``SetFreq`` und ``GetFreq`` folgt der Gerätebasisklasse. Messwerte werden als SCUQ-Quantities mit Einheit und Unsicherheit geliefert. ``_internal_unit`` bezeichnet die feste geräteinterne Einheit; die Kanaleinheit aus der :doc:`INI-Datei <../configuration/instrument-data>` ist die vom Anwender angeforderte Einheit. Umrechnungen erfolgen zentral über ``mpylab.tools.uconv``. ``Trigger`` startet eine Erfassung, sofern die Geräteklasse dies unterstützt. ``GetData`` liest blockierend. ``GetDataNB(retrigger=...)`` folgt der familienweiten Nonblocking-Regel und darf bei einem blockierenden Gerät auf ``GetData`` zurückfallen. Feldsonden liefern ihre drei Komponenten immer in der Reihenfolge ``probe_x``, ``probe_y``, ``probe_z``; die Abbildung auf das Zellkoordinatensystem erfolgt außerhalb des Gerätetreibers. Sicherheit und Beenden ---------------------- ``RFOff`` ist bei HF-Quellen eine Sicherheitsfunktion und muss ohne Abhängigkeit von UI-Zuständen erreichbar bleiben. ``Quit`` bringt das Gerät in einen sicheren Zustand und gibt anschließend Kommunikationsressourcen frei. Fehler beim Abschalten dürfen den Versuch, den Bus zu schließen, nicht verhindern. Gerätegrenzen wie ``MAXIN`` werden als Quantity aus INI-/DAT-Daten gelesen. MGraph berücksichtigt sie über ``AmplifierProtect`` und ``MaxSafeLevel`` für alle aktiven Pfade. Ein Schutzlimit darf nicht stillschweigend überschritten werden. Feldsonden können zusätzlich ``GetBatteryState()`` anbieten. Die Rückgabe ist ``(status, state)``; ``None`` bedeutet, dass kein Zustand verfügbar ist, ein negativer Zustand meldet eine niedrige Batterie. MGraph akzeptiert während der Übergangszeit auch die alte Schreibweise ``getBatteryState``. Virtuelle und passive Geräte ---------------------------- Ein virtueller Treiber hält denselben öffentlichen Vertrag wie sein reales Gegenstück ein. Er darf Werte aus einem anderen virtuellen Graphgerät ableiten, beispielsweise Leistung und Feldstärke aus dem Pegel eines Signalgenerators. ``MGraph.CreateDevices()`` bindet solche Quellen graphlokal; Zustände dürfen nicht zwischen unabhängigen Graphinstanzen geteilt werden. Passive Geräte wie Kabel, Dämpfungsglieder und Antennen öffnen keinen Bus. Sie lesen ihre frequenzabhängigen Daten aus DAT-Dateien und liefern Pfadkorrekturen als SCUQ-Quantity. Ein vollständiger virtueller Graph prüft damit nicht nur einzelne Treiber, sondern auch Conditions, Pfadauswahl, Einheiten und gekoppelte Messwerte. Prüfung konkreter Treiber ------------------------- Jede Gerätefamilie besitzt Vertragstests. Ein neuer konkreter Treiber wird in den passenden Test aufgenommen und muss insbesondere nachweisen: * identische öffentliche Signaturen; * korrekte Rückgabeformen, Einheiten und Kanalreihenfolgen; * Validierung vor Hardwarezugriff; * Initialisierung mit und ohne Bus; * sichere Fehlerweitergabe und ``Quit``; * instanzlokalen Zustand; * Verhalten von Trigger und ``GetDataNB``. Danach folgen Protokolltests, ein virtueller MGraph-Integrationstest und erst dann der gestufte Hardwaretest. Der vollständige Ablauf steht unter :doc:`Testen und Inbetriebnehmen `. Für gemeinsam genutzte physische Geräte gilt zusätzlich das :doc:`Mehrkanalmodell `.