Gerätetreiber entwickeln ======================== Ein Gerätetreiber übersetzt die öffentliche API einer Geräteklasse in das Protokoll eines konkreten Geräts. Kommunikationsdetails und fachliche Messabläufe bleiben außerhalb des spezifischen Treibers. Die verbindlichen Laufzeitregeln für Statuscodes, Rückgabeformen, Initialisierung, Busstrategie, Quantities und Safety beschreibt :doc:`Gemeinsames Gerätetreiber-Verhalten `. Diese Seite konzentriert sich auf die Implementierung eines konkreten Treibers. Die richtige Basisklasse ------------------------ Ein Leistungsmesser erbt von ``POWERMETER``, ein Empfänger von ``RECEIVER`` und ein Signalgenerator von ``SIGNALGENERATOR``. Diese Basisklassen definieren Methodennamen, Einheitenkonvention, Konfigurationsschema und gemeinsame Fallbacks. Direktes Erben von ``DRIVER`` ist nur für eine neue Geräteklasse sinnvoll. .. code-block:: python from mpylab.device.powermeter import POWERMETER as BasePowerMeter class POWERMETER(BasePowerMeter): def __init__(self, SearchPaths=None): super().__init__(SearchPaths=SearchPaths) self._internal_unit = "dBm" Rückgabeform und Signatur folgen immer der Basisklasse. Abfragen liefern meist ``(status, value)``; Aktionsmethoden können auch nur ``status`` liefern. Messwerte werden als SCUQ-Quantity in der angeforderten Kanaleinheit zurückgegeben. Initialisierung --------------- Alle gepflegten Treiber verwenden die Signatur ``Init(ini=None, channel=None, ignore_bus=None)``. ``None`` wählt den gerätespezifischen Standard: aktive Geräte öffnen normalerweise ihren Bus, rein passive und virtuelle Geräte setzen ``_default_ignore_bus = True``. Explizites ``True`` oder ``False`` überschreibt diesen Standard. ``super().Init(ini, channel, ignore_bus=ignore_bus)`` liest die INI-Datei, löst die Busstrategie auf und richtet gegebenenfalls die Kommunikationsklasse ein. Das Ergebnis steht anschließend in ``self.bus_ignored``. Ein konkreter aktiver Treiber kehrt bei ``self.error`` oder ``self.bus_ignored`` zurück, bevor er Presets, Moduswechsel oder andere Gerätebefehle sendet. Ein Fehler beim Moduswechsel oder bei einer Bereichseinstellung darf nicht stillschweigend als Erfolg behandelt werden. Kommunikation ------------- ``DRIVER`` stellt ``write``, ``read`` und ``query`` über eine Kommunikationsklasse bereit. GPIB, VISA, Prologix und Debug-/Virtualbetrieb werden dadurch vereinheitlicht. Direkter Zugriff auf ``self.dev`` ist nur begründet, wenn die gemeinsame Schnittstelle eine benötigte Funktion nicht abbildet. Antworten werden vollständig konsumiert. Mehrzeilige oder zusätzlich terminierte Geräteantworten benötigen eine klar benannte Drain-Strategie, damit kein Rest die nächste Abfrage verfälscht. Einheiten --------- ``_internal_unit`` ist die feste Einheit, in der das Gerät Werte liefert oder akzeptiert. Die Kanaleinheit aus der INI-Datei ist die vom Anwender angeforderte Einheit. Umrechnungen erfolgen über ``mpylab.tools.uconv`` und nicht über lokale dB-Formeln. Virtueller Treiber und Tests ---------------------------- Für neue Geräteklassen oder komplexe APIs ist ein virtueller Treiber mit derselben öffentlichen API sinnvoll. Tests decken mindestens ab: * Initialisierung ohne Hardware; * Befehlsformat und Antwortparser; * Einheiten und Unsicherheit; * ungültige Parameter und Gerätestatus; * Mehrkanalinstanzen ohne gemeinsam veränderlichen Zustand; * Trigger-, Nonblocking- und Timeout-Verhalten; * sicheres ``Quit`` und RF-Off, falls vorhanden. Inline-Smoke-Tests und Beispiel-INI-Dateien erleichtern den späteren Hardwaretest, ersetzen aber keine automatisierten Tests. Treiber, die mehrere logische Graphknoten über ein physisches Gerät bereitstellen, müssen zusätzlich dem :doc:`Mehrkanalmodell aus gemeinsamem Controller und Kanalinstanzen ` folgen.